1ed0d50c3Schristos // aarch64.cc -- aarch64 target support for gold.
2ed0d50c3Schristos
3*b88e3e88Schristos // Copyright (C) 2014-2020 Free Software Foundation, Inc.
4ed0d50c3Schristos // Written by Jing Yu <jingyu@google.com> and Han Shen <shenhan@google.com>.
5ed0d50c3Schristos
6ed0d50c3Schristos // This file is part of gold.
7ed0d50c3Schristos
8ed0d50c3Schristos // This program is free software; you can redistribute it and/or modify
9ed0d50c3Schristos // it under the terms of the GNU General Public License as published by
10ed0d50c3Schristos // the Free Software Foundation; either version 3 of the License, or
11ed0d50c3Schristos // (at your option) any later version.
12ed0d50c3Schristos
13ed0d50c3Schristos // This program is distributed in the hope that it will be useful,
14ed0d50c3Schristos // but WITHOUT ANY WARRANTY; without even the implied warranty of
15ed0d50c3Schristos // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16ed0d50c3Schristos // GNU General Public License for more details.
17ed0d50c3Schristos
18ed0d50c3Schristos // You should have received a copy of the GNU General Public License
19ed0d50c3Schristos // along with this program; if not, write to the Free Software
20ed0d50c3Schristos // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21ed0d50c3Schristos // MA 02110-1301, USA.
22ed0d50c3Schristos
23ed0d50c3Schristos #include "gold.h"
24ed0d50c3Schristos
25ed0d50c3Schristos #include <cstring>
26ed0d50c3Schristos #include <map>
27ed0d50c3Schristos #include <set>
28ed0d50c3Schristos
29ed0d50c3Schristos #include "elfcpp.h"
30ed0d50c3Schristos #include "dwarf.h"
31ed0d50c3Schristos #include "parameters.h"
32ed0d50c3Schristos #include "reloc.h"
33ed0d50c3Schristos #include "aarch64.h"
34ed0d50c3Schristos #include "object.h"
35ed0d50c3Schristos #include "symtab.h"
36ed0d50c3Schristos #include "layout.h"
37ed0d50c3Schristos #include "output.h"
38ed0d50c3Schristos #include "copy-relocs.h"
39ed0d50c3Schristos #include "target.h"
40ed0d50c3Schristos #include "target-reloc.h"
41ed0d50c3Schristos #include "target-select.h"
42ed0d50c3Schristos #include "tls.h"
43ed0d50c3Schristos #include "freebsd.h"
44ed0d50c3Schristos #include "nacl.h"
45ed0d50c3Schristos #include "gc.h"
46ed0d50c3Schristos #include "icf.h"
47ed0d50c3Schristos #include "aarch64-reloc-property.h"
48ed0d50c3Schristos
49ed0d50c3Schristos // The first three .got.plt entries are reserved.
50ed0d50c3Schristos const int32_t AARCH64_GOTPLT_RESERVE_COUNT = 3;
51ed0d50c3Schristos
52ed0d50c3Schristos
53ed0d50c3Schristos namespace
54ed0d50c3Schristos {
55ed0d50c3Schristos
56ed0d50c3Schristos using namespace gold;
57ed0d50c3Schristos
58ed0d50c3Schristos template<int size, bool big_endian>
59ed0d50c3Schristos class Output_data_plt_aarch64;
60ed0d50c3Schristos
61ed0d50c3Schristos template<int size, bool big_endian>
62ed0d50c3Schristos class Output_data_plt_aarch64_standard;
63ed0d50c3Schristos
64ed0d50c3Schristos template<int size, bool big_endian>
65ed0d50c3Schristos class Target_aarch64;
66ed0d50c3Schristos
67ed0d50c3Schristos template<int size, bool big_endian>
68ed0d50c3Schristos class AArch64_relocate_functions;
69ed0d50c3Schristos
70ed0d50c3Schristos // Utility class dealing with insns. This is ported from macros in
71ed0d50c3Schristos // bfd/elfnn-aarch64.cc, but wrapped inside a class as static members. This
72ed0d50c3Schristos // class is used in erratum sequence scanning.
73ed0d50c3Schristos
74ed0d50c3Schristos template<bool big_endian>
75ed0d50c3Schristos class AArch64_insn_utilities
76ed0d50c3Schristos {
77ed0d50c3Schristos public:
78ed0d50c3Schristos typedef typename elfcpp::Swap<32, big_endian>::Valtype Insntype;
79ed0d50c3Schristos
80ed0d50c3Schristos static const int BYTES_PER_INSN;
81ed0d50c3Schristos
82ed0d50c3Schristos // Zero register encoding - 31.
83ed0d50c3Schristos static const unsigned int AARCH64_ZR;
84ed0d50c3Schristos
85ed0d50c3Schristos static unsigned int
aarch64_bit(Insntype insn,int pos)86ed0d50c3Schristos aarch64_bit(Insntype insn, int pos)
87ed0d50c3Schristos { return ((1 << pos) & insn) >> pos; }
88ed0d50c3Schristos
89ed0d50c3Schristos static unsigned int
aarch64_bits(Insntype insn,int pos,int l)90ed0d50c3Schristos aarch64_bits(Insntype insn, int pos, int l)
91ed0d50c3Schristos { return (insn >> pos) & ((1 << l) - 1); }
92ed0d50c3Schristos
93ed0d50c3Schristos // Get the encoding field "op31" of 3-source data processing insns. "op31" is
94ed0d50c3Schristos // the name defined in armv8 insn manual C3.5.9.
95ed0d50c3Schristos static unsigned int
aarch64_op31(Insntype insn)96ed0d50c3Schristos aarch64_op31(Insntype insn)
97ed0d50c3Schristos { return aarch64_bits(insn, 21, 3); }
98ed0d50c3Schristos
99ed0d50c3Schristos // Get the encoding field "ra" of 3-source data processing insns. "ra" is the
100ed0d50c3Schristos // third source register. See armv8 insn manual C3.5.9.
101ed0d50c3Schristos static unsigned int
aarch64_ra(Insntype insn)102ed0d50c3Schristos aarch64_ra(Insntype insn)
103ed0d50c3Schristos { return aarch64_bits(insn, 10, 5); }
104ed0d50c3Schristos
105ed0d50c3Schristos static bool
is_adr(const Insntype insn)106ed0d50c3Schristos is_adr(const Insntype insn)
107ed0d50c3Schristos { return (insn & 0x9F000000) == 0x10000000; }
108ed0d50c3Schristos
109ed0d50c3Schristos static bool
is_adrp(const Insntype insn)110ed0d50c3Schristos is_adrp(const Insntype insn)
111ed0d50c3Schristos { return (insn & 0x9F000000) == 0x90000000; }
112ed0d50c3Schristos
11306324dcfSchristos static bool
is_mrs_tpidr_el0(const Insntype insn)11406324dcfSchristos is_mrs_tpidr_el0(const Insntype insn)
11506324dcfSchristos { return (insn & 0xFFFFFFE0) == 0xd53bd040; }
11606324dcfSchristos
117ed0d50c3Schristos static unsigned int
aarch64_rm(const Insntype insn)118ed0d50c3Schristos aarch64_rm(const Insntype insn)
119ed0d50c3Schristos { return aarch64_bits(insn, 16, 5); }
120ed0d50c3Schristos
121ed0d50c3Schristos static unsigned int
aarch64_rn(const Insntype insn)122ed0d50c3Schristos aarch64_rn(const Insntype insn)
123ed0d50c3Schristos { return aarch64_bits(insn, 5, 5); }
124ed0d50c3Schristos
125ed0d50c3Schristos static unsigned int
aarch64_rd(const Insntype insn)126ed0d50c3Schristos aarch64_rd(const Insntype insn)
127ed0d50c3Schristos { return aarch64_bits(insn, 0, 5); }
128ed0d50c3Schristos
129ed0d50c3Schristos static unsigned int
aarch64_rt(const Insntype insn)130ed0d50c3Schristos aarch64_rt(const Insntype insn)
131ed0d50c3Schristos { return aarch64_bits(insn, 0, 5); }
132ed0d50c3Schristos
133ed0d50c3Schristos static unsigned int
aarch64_rt2(const Insntype insn)134ed0d50c3Schristos aarch64_rt2(const Insntype insn)
135ed0d50c3Schristos { return aarch64_bits(insn, 10, 5); }
136ed0d50c3Schristos
137ed0d50c3Schristos // Encode imm21 into adr. Signed imm21 is in the range of [-1M, 1M).
138ed0d50c3Schristos static Insntype
aarch64_adr_encode_imm(Insntype adr,int imm21)139ed0d50c3Schristos aarch64_adr_encode_imm(Insntype adr, int imm21)
140ed0d50c3Schristos {
141ed0d50c3Schristos gold_assert(is_adr(adr));
142ed0d50c3Schristos gold_assert(-(1 << 20) <= imm21 && imm21 < (1 << 20));
143ed0d50c3Schristos const int mask19 = (1 << 19) - 1;
144ed0d50c3Schristos const int mask2 = 3;
145ed0d50c3Schristos adr &= ~((mask19 << 5) | (mask2 << 29));
146ed0d50c3Schristos adr |= ((imm21 & mask2) << 29) | (((imm21 >> 2) & mask19) << 5);
147ed0d50c3Schristos return adr;
148ed0d50c3Schristos }
149ed0d50c3Schristos
150ed0d50c3Schristos // Retrieve encoded adrp 33-bit signed imm value. This value is obtained by
151ed0d50c3Schristos // 21-bit signed imm encoded in the insn multiplied by 4k (page size) and
152ed0d50c3Schristos // 64-bit sign-extended, resulting in [-4G, 4G) with 12-lsb being 0.
153ed0d50c3Schristos static int64_t
aarch64_adrp_decode_imm(const Insntype adrp)154ed0d50c3Schristos aarch64_adrp_decode_imm(const Insntype adrp)
155ed0d50c3Schristos {
156ed0d50c3Schristos const int mask19 = (1 << 19) - 1;
157ed0d50c3Schristos const int mask2 = 3;
158ed0d50c3Schristos gold_assert(is_adrp(adrp));
159ed0d50c3Schristos // 21-bit imm encoded in adrp.
160ed0d50c3Schristos uint64_t imm = ((adrp >> 29) & mask2) | (((adrp >> 5) & mask19) << 2);
161ed0d50c3Schristos // Retrieve msb of 21-bit-signed imm for sign extension.
162ed0d50c3Schristos uint64_t msbt = (imm >> 20) & 1;
16306324dcfSchristos // Real value is imm multiplied by 4k. Value now has 33-bit information.
164ed0d50c3Schristos int64_t value = imm << 12;
165ed0d50c3Schristos // Sign extend to 64-bit by repeating msbt 31 (64-33) times and merge it
166ed0d50c3Schristos // with value.
167ed0d50c3Schristos return ((((uint64_t)(1) << 32) - msbt) << 33) | value;
168ed0d50c3Schristos }
169ed0d50c3Schristos
170ed0d50c3Schristos static bool
aarch64_b(const Insntype insn)171ed0d50c3Schristos aarch64_b(const Insntype insn)
172ed0d50c3Schristos { return (insn & 0xFC000000) == 0x14000000; }
173ed0d50c3Schristos
174ed0d50c3Schristos static bool
aarch64_bl(const Insntype insn)175ed0d50c3Schristos aarch64_bl(const Insntype insn)
176ed0d50c3Schristos { return (insn & 0xFC000000) == 0x94000000; }
177ed0d50c3Schristos
178ed0d50c3Schristos static bool
aarch64_blr(const Insntype insn)179ed0d50c3Schristos aarch64_blr(const Insntype insn)
180ed0d50c3Schristos { return (insn & 0xFFFFFC1F) == 0xD63F0000; }
181ed0d50c3Schristos
182ed0d50c3Schristos static bool
aarch64_br(const Insntype insn)183ed0d50c3Schristos aarch64_br(const Insntype insn)
184ed0d50c3Schristos { return (insn & 0xFFFFFC1F) == 0xD61F0000; }
185ed0d50c3Schristos
186ed0d50c3Schristos // All ld/st ops. See C4-182 of the ARM ARM. The encoding space for
187ed0d50c3Schristos // LD_PCREL, LDST_RO, LDST_UI and LDST_UIMM cover prefetch ops.
188ed0d50c3Schristos static bool
aarch64_ld(Insntype insn)189ed0d50c3Schristos aarch64_ld(Insntype insn) { return aarch64_bit(insn, 22) == 1; }
190ed0d50c3Schristos
191ed0d50c3Schristos static bool
aarch64_ldst(Insntype insn)192ed0d50c3Schristos aarch64_ldst(Insntype insn)
193ed0d50c3Schristos { return (insn & 0x0a000000) == 0x08000000; }
194ed0d50c3Schristos
195ed0d50c3Schristos static bool
aarch64_ldst_ex(Insntype insn)196ed0d50c3Schristos aarch64_ldst_ex(Insntype insn)
197ed0d50c3Schristos { return (insn & 0x3f000000) == 0x08000000; }
198ed0d50c3Schristos
199ed0d50c3Schristos static bool
aarch64_ldst_pcrel(Insntype insn)200ed0d50c3Schristos aarch64_ldst_pcrel(Insntype insn)
201ed0d50c3Schristos { return (insn & 0x3b000000) == 0x18000000; }
202ed0d50c3Schristos
203ed0d50c3Schristos static bool
aarch64_ldst_nap(Insntype insn)204ed0d50c3Schristos aarch64_ldst_nap(Insntype insn)
205ed0d50c3Schristos { return (insn & 0x3b800000) == 0x28000000; }
206ed0d50c3Schristos
207ed0d50c3Schristos static bool
aarch64_ldstp_pi(Insntype insn)208ed0d50c3Schristos aarch64_ldstp_pi(Insntype insn)
209ed0d50c3Schristos { return (insn & 0x3b800000) == 0x28800000; }
210ed0d50c3Schristos
211ed0d50c3Schristos static bool
aarch64_ldstp_o(Insntype insn)212ed0d50c3Schristos aarch64_ldstp_o(Insntype insn)
213ed0d50c3Schristos { return (insn & 0x3b800000) == 0x29000000; }
214ed0d50c3Schristos
215ed0d50c3Schristos static bool
aarch64_ldstp_pre(Insntype insn)216ed0d50c3Schristos aarch64_ldstp_pre(Insntype insn)
217ed0d50c3Schristos { return (insn & 0x3b800000) == 0x29800000; }
218ed0d50c3Schristos
219ed0d50c3Schristos static bool
aarch64_ldst_ui(Insntype insn)220ed0d50c3Schristos aarch64_ldst_ui(Insntype insn)
221ed0d50c3Schristos { return (insn & 0x3b200c00) == 0x38000000; }
222ed0d50c3Schristos
223ed0d50c3Schristos static bool
aarch64_ldst_piimm(Insntype insn)224ed0d50c3Schristos aarch64_ldst_piimm(Insntype insn)
225ed0d50c3Schristos { return (insn & 0x3b200c00) == 0x38000400; }
226ed0d50c3Schristos
227ed0d50c3Schristos static bool
aarch64_ldst_u(Insntype insn)228ed0d50c3Schristos aarch64_ldst_u(Insntype insn)
229ed0d50c3Schristos { return (insn & 0x3b200c00) == 0x38000800; }
230ed0d50c3Schristos
231ed0d50c3Schristos static bool
aarch64_ldst_preimm(Insntype insn)232ed0d50c3Schristos aarch64_ldst_preimm(Insntype insn)
233ed0d50c3Schristos { return (insn & 0x3b200c00) == 0x38000c00; }
234ed0d50c3Schristos
235ed0d50c3Schristos static bool
aarch64_ldst_ro(Insntype insn)236ed0d50c3Schristos aarch64_ldst_ro(Insntype insn)
237ed0d50c3Schristos { return (insn & 0x3b200c00) == 0x38200800; }
238ed0d50c3Schristos
239ed0d50c3Schristos static bool
aarch64_ldst_uimm(Insntype insn)240ed0d50c3Schristos aarch64_ldst_uimm(Insntype insn)
241ed0d50c3Schristos { return (insn & 0x3b000000) == 0x39000000; }
242ed0d50c3Schristos
243ed0d50c3Schristos static bool
aarch64_ldst_simd_m(Insntype insn)244ed0d50c3Schristos aarch64_ldst_simd_m(Insntype insn)
245ed0d50c3Schristos { return (insn & 0xbfbf0000) == 0x0c000000; }
246ed0d50c3Schristos
247ed0d50c3Schristos static bool
aarch64_ldst_simd_m_pi(Insntype insn)248ed0d50c3Schristos aarch64_ldst_simd_m_pi(Insntype insn)
249ed0d50c3Schristos { return (insn & 0xbfa00000) == 0x0c800000; }
250ed0d50c3Schristos
251ed0d50c3Schristos static bool
aarch64_ldst_simd_s(Insntype insn)252ed0d50c3Schristos aarch64_ldst_simd_s(Insntype insn)
253ed0d50c3Schristos { return (insn & 0xbf9f0000) == 0x0d000000; }
254ed0d50c3Schristos
255ed0d50c3Schristos static bool
aarch64_ldst_simd_s_pi(Insntype insn)256ed0d50c3Schristos aarch64_ldst_simd_s_pi(Insntype insn)
257ed0d50c3Schristos { return (insn & 0xbf800000) == 0x0d800000; }
258ed0d50c3Schristos
259ed0d50c3Schristos // Classify an INSN if it is indeed a load/store. Return true if INSN is a
260ed0d50c3Schristos // LD/ST instruction otherwise return false. For scalar LD/ST instructions
261ed0d50c3Schristos // PAIR is FALSE, RT is returned and RT2 is set equal to RT. For LD/ST pair
262ed0d50c3Schristos // instructions PAIR is TRUE, RT and RT2 are returned.
263ed0d50c3Schristos static bool
aarch64_mem_op_p(Insntype insn,unsigned int * rt,unsigned int * rt2,bool * pair,bool * load)264ed0d50c3Schristos aarch64_mem_op_p(Insntype insn, unsigned int *rt, unsigned int *rt2,
265ed0d50c3Schristos bool *pair, bool *load)
266ed0d50c3Schristos {
267ed0d50c3Schristos uint32_t opcode;
268ed0d50c3Schristos unsigned int r;
269ed0d50c3Schristos uint32_t opc = 0;
270ed0d50c3Schristos uint32_t v = 0;
271ed0d50c3Schristos uint32_t opc_v = 0;
272ed0d50c3Schristos
27306324dcfSchristos /* Bail out quickly if INSN doesn't fall into the load-store
274ed0d50c3Schristos encoding space. */
275ed0d50c3Schristos if (!aarch64_ldst (insn))
276ed0d50c3Schristos return false;
277ed0d50c3Schristos
278ed0d50c3Schristos *pair = false;
279ed0d50c3Schristos *load = false;
280ed0d50c3Schristos if (aarch64_ldst_ex (insn))
281ed0d50c3Schristos {
282ed0d50c3Schristos *rt = aarch64_rt (insn);
283ed0d50c3Schristos *rt2 = *rt;
284ed0d50c3Schristos if (aarch64_bit (insn, 21) == 1)
285ed0d50c3Schristos {
286ed0d50c3Schristos *pair = true;
287ed0d50c3Schristos *rt2 = aarch64_rt2 (insn);
288ed0d50c3Schristos }
289ed0d50c3Schristos *load = aarch64_ld (insn);
290ed0d50c3Schristos return true;
291ed0d50c3Schristos }
292ed0d50c3Schristos else if (aarch64_ldst_nap (insn)
293ed0d50c3Schristos || aarch64_ldstp_pi (insn)
294ed0d50c3Schristos || aarch64_ldstp_o (insn)
295ed0d50c3Schristos || aarch64_ldstp_pre (insn))
296ed0d50c3Schristos {
297ed0d50c3Schristos *pair = true;
298ed0d50c3Schristos *rt = aarch64_rt (insn);
299ed0d50c3Schristos *rt2 = aarch64_rt2 (insn);
300ed0d50c3Schristos *load = aarch64_ld (insn);
301ed0d50c3Schristos return true;
302ed0d50c3Schristos }
303ed0d50c3Schristos else if (aarch64_ldst_pcrel (insn)
304ed0d50c3Schristos || aarch64_ldst_ui (insn)
305ed0d50c3Schristos || aarch64_ldst_piimm (insn)
306ed0d50c3Schristos || aarch64_ldst_u (insn)
307ed0d50c3Schristos || aarch64_ldst_preimm (insn)
308ed0d50c3Schristos || aarch64_ldst_ro (insn)
309ed0d50c3Schristos || aarch64_ldst_uimm (insn))
310ed0d50c3Schristos {
311ed0d50c3Schristos *rt = aarch64_rt (insn);
312ed0d50c3Schristos *rt2 = *rt;
313ed0d50c3Schristos if (aarch64_ldst_pcrel (insn))
314ed0d50c3Schristos *load = true;
315ed0d50c3Schristos opc = aarch64_bits (insn, 22, 2);
316ed0d50c3Schristos v = aarch64_bit (insn, 26);
317ed0d50c3Schristos opc_v = opc | (v << 2);
318ed0d50c3Schristos *load = (opc_v == 1 || opc_v == 2 || opc_v == 3
319ed0d50c3Schristos || opc_v == 5 || opc_v == 7);
320ed0d50c3Schristos return true;
321ed0d50c3Schristos }
322ed0d50c3Schristos else if (aarch64_ldst_simd_m (insn)
323ed0d50c3Schristos || aarch64_ldst_simd_m_pi (insn))
324ed0d50c3Schristos {
325ed0d50c3Schristos *rt = aarch64_rt (insn);
326ed0d50c3Schristos *load = aarch64_bit (insn, 22);
327ed0d50c3Schristos opcode = (insn >> 12) & 0xf;
328ed0d50c3Schristos switch (opcode)
329ed0d50c3Schristos {
330ed0d50c3Schristos case 0:
331ed0d50c3Schristos case 2:
332ed0d50c3Schristos *rt2 = *rt + 3;
333ed0d50c3Schristos break;
334ed0d50c3Schristos
335ed0d50c3Schristos case 4:
336ed0d50c3Schristos case 6:
337ed0d50c3Schristos *rt2 = *rt + 2;
338ed0d50c3Schristos break;
339ed0d50c3Schristos
340ed0d50c3Schristos case 7:
341ed0d50c3Schristos *rt2 = *rt;
342ed0d50c3Schristos break;
343ed0d50c3Schristos
344ed0d50c3Schristos case 8:
345ed0d50c3Schristos case 10:
346ed0d50c3Schristos *rt2 = *rt + 1;
347ed0d50c3Schristos break;
348ed0d50c3Schristos
349ed0d50c3Schristos default:
350ed0d50c3Schristos return false;
351ed0d50c3Schristos }
352ed0d50c3Schristos return true;
353ed0d50c3Schristos }
354ed0d50c3Schristos else if (aarch64_ldst_simd_s (insn)
355ed0d50c3Schristos || aarch64_ldst_simd_s_pi (insn))
356ed0d50c3Schristos {
357ed0d50c3Schristos *rt = aarch64_rt (insn);
358ed0d50c3Schristos r = (insn >> 21) & 1;
359ed0d50c3Schristos *load = aarch64_bit (insn, 22);
360ed0d50c3Schristos opcode = (insn >> 13) & 0x7;
361ed0d50c3Schristos switch (opcode)
362ed0d50c3Schristos {
363ed0d50c3Schristos case 0:
364ed0d50c3Schristos case 2:
365ed0d50c3Schristos case 4:
366ed0d50c3Schristos *rt2 = *rt + r;
367ed0d50c3Schristos break;
368ed0d50c3Schristos
369ed0d50c3Schristos case 1:
370ed0d50c3Schristos case 3:
371ed0d50c3Schristos case 5:
372ed0d50c3Schristos *rt2 = *rt + (r == 0 ? 2 : 3);
373ed0d50c3Schristos break;
374ed0d50c3Schristos
375ed0d50c3Schristos case 6:
376ed0d50c3Schristos *rt2 = *rt + r;
377ed0d50c3Schristos break;
378ed0d50c3Schristos
379ed0d50c3Schristos case 7:
380ed0d50c3Schristos *rt2 = *rt + (r == 0 ? 2 : 3);
381ed0d50c3Schristos break;
382ed0d50c3Schristos
383ed0d50c3Schristos default:
384ed0d50c3Schristos return false;
385ed0d50c3Schristos }
386ed0d50c3Schristos return true;
387ed0d50c3Schristos }
388ed0d50c3Schristos return false;
389ed0d50c3Schristos } // End of "aarch64_mem_op_p".
390ed0d50c3Schristos
391ed0d50c3Schristos // Return true if INSN is mac insn.
392ed0d50c3Schristos static bool
aarch64_mac(Insntype insn)393ed0d50c3Schristos aarch64_mac(Insntype insn)
394ed0d50c3Schristos { return (insn & 0xff000000) == 0x9b000000; }
395ed0d50c3Schristos
396ed0d50c3Schristos // Return true if INSN is multiply-accumulate.
397ed0d50c3Schristos // (This is similar to implementaton in elfnn-aarch64.c.)
398ed0d50c3Schristos static bool
aarch64_mlxl(Insntype insn)399ed0d50c3Schristos aarch64_mlxl(Insntype insn)
400ed0d50c3Schristos {
401ed0d50c3Schristos uint32_t op31 = aarch64_op31(insn);
402ed0d50c3Schristos if (aarch64_mac(insn)
403ed0d50c3Schristos && (op31 == 0 || op31 == 1 || op31 == 5)
404ed0d50c3Schristos /* Exclude MUL instructions which are encoded as a multiple-accumulate
405ed0d50c3Schristos with RA = XZR. */
406ed0d50c3Schristos && aarch64_ra(insn) != AARCH64_ZR)
407ed0d50c3Schristos {
408ed0d50c3Schristos return true;
409ed0d50c3Schristos }
410ed0d50c3Schristos return false;
411ed0d50c3Schristos }
412ed0d50c3Schristos }; // End of "AArch64_insn_utilities".
413ed0d50c3Schristos
414ed0d50c3Schristos
415ed0d50c3Schristos // Insn length in byte.
416ed0d50c3Schristos
417ed0d50c3Schristos template<bool big_endian>
418ed0d50c3Schristos const int AArch64_insn_utilities<big_endian>::BYTES_PER_INSN = 4;
419ed0d50c3Schristos
420ed0d50c3Schristos
421ed0d50c3Schristos // Zero register encoding - 31.
422ed0d50c3Schristos
423ed0d50c3Schristos template<bool big_endian>
424ed0d50c3Schristos const unsigned int AArch64_insn_utilities<big_endian>::AARCH64_ZR = 0x1f;
425ed0d50c3Schristos
426ed0d50c3Schristos
427ed0d50c3Schristos // Output_data_got_aarch64 class.
428ed0d50c3Schristos
429ed0d50c3Schristos template<int size, bool big_endian>
430ed0d50c3Schristos class Output_data_got_aarch64 : public Output_data_got<size, big_endian>
431ed0d50c3Schristos {
432ed0d50c3Schristos public:
433ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Addr Valtype;
Output_data_got_aarch64(Symbol_table * symtab,Layout * layout)434ed0d50c3Schristos Output_data_got_aarch64(Symbol_table* symtab, Layout* layout)
435ed0d50c3Schristos : Output_data_got<size, big_endian>(),
436ed0d50c3Schristos symbol_table_(symtab), layout_(layout)
437ed0d50c3Schristos { }
438ed0d50c3Schristos
439ed0d50c3Schristos // Add a static entry for the GOT entry at OFFSET. GSYM is a global
440ed0d50c3Schristos // symbol and R_TYPE is the code of a dynamic relocation that needs to be
441ed0d50c3Schristos // applied in a static link.
442ed0d50c3Schristos void
add_static_reloc(unsigned int got_offset,unsigned int r_type,Symbol * gsym)443ed0d50c3Schristos add_static_reloc(unsigned int got_offset, unsigned int r_type, Symbol* gsym)
444ed0d50c3Schristos { this->static_relocs_.push_back(Static_reloc(got_offset, r_type, gsym)); }
445ed0d50c3Schristos
446ed0d50c3Schristos
447ed0d50c3Schristos // Add a static reloc for the GOT entry at OFFSET. RELOBJ is an object
448ed0d50c3Schristos // defining a local symbol with INDEX. R_TYPE is the code of a dynamic
449ed0d50c3Schristos // relocation that needs to be applied in a static link.
450ed0d50c3Schristos void
add_static_reloc(unsigned int got_offset,unsigned int r_type,Sized_relobj_file<size,big_endian> * relobj,unsigned int index)451ed0d50c3Schristos add_static_reloc(unsigned int got_offset, unsigned int r_type,
452ed0d50c3Schristos Sized_relobj_file<size, big_endian>* relobj,
453ed0d50c3Schristos unsigned int index)
454ed0d50c3Schristos {
455ed0d50c3Schristos this->static_relocs_.push_back(Static_reloc(got_offset, r_type, relobj,
456ed0d50c3Schristos index));
457ed0d50c3Schristos }
458ed0d50c3Schristos
459ed0d50c3Schristos
460ed0d50c3Schristos protected:
461ed0d50c3Schristos // Write out the GOT table.
462ed0d50c3Schristos void
do_write(Output_file * of)463ed0d50c3Schristos do_write(Output_file* of) {
464ed0d50c3Schristos // The first entry in the GOT is the address of the .dynamic section.
465ed0d50c3Schristos gold_assert(this->data_size() >= size / 8);
466ed0d50c3Schristos Output_section* dynamic = this->layout_->dynamic_section();
467ed0d50c3Schristos Valtype dynamic_addr = dynamic == NULL ? 0 : dynamic->address();
468ed0d50c3Schristos this->replace_constant(0, dynamic_addr);
469ed0d50c3Schristos Output_data_got<size, big_endian>::do_write(of);
470ed0d50c3Schristos
471ed0d50c3Schristos // Handling static relocs
472ed0d50c3Schristos if (this->static_relocs_.empty())
473ed0d50c3Schristos return;
474ed0d50c3Schristos
475ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
476ed0d50c3Schristos
477ed0d50c3Schristos gold_assert(parameters->doing_static_link());
478ed0d50c3Schristos const off_t offset = this->offset();
479ed0d50c3Schristos const section_size_type oview_size =
480ed0d50c3Schristos convert_to_section_size_type(this->data_size());
481ed0d50c3Schristos unsigned char* const oview = of->get_output_view(offset, oview_size);
482ed0d50c3Schristos
483ed0d50c3Schristos Output_segment* tls_segment = this->layout_->tls_segment();
484ed0d50c3Schristos gold_assert(tls_segment != NULL);
485ed0d50c3Schristos
486ed0d50c3Schristos AArch64_address aligned_tcb_address =
487ed0d50c3Schristos align_address(Target_aarch64<size, big_endian>::TCB_SIZE,
488ed0d50c3Schristos tls_segment->maximum_alignment());
489ed0d50c3Schristos
490ed0d50c3Schristos for (size_t i = 0; i < this->static_relocs_.size(); ++i)
491ed0d50c3Schristos {
492ed0d50c3Schristos Static_reloc& reloc(this->static_relocs_[i]);
493ed0d50c3Schristos AArch64_address value;
494ed0d50c3Schristos
495ed0d50c3Schristos if (!reloc.symbol_is_global())
496ed0d50c3Schristos {
497ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object = reloc.relobj();
498ed0d50c3Schristos const Symbol_value<size>* psymval =
499ed0d50c3Schristos reloc.relobj()->local_symbol(reloc.index());
500ed0d50c3Schristos
501ed0d50c3Schristos // We are doing static linking. Issue an error and skip this
502ed0d50c3Schristos // relocation if the symbol is undefined or in a discarded_section.
503ed0d50c3Schristos bool is_ordinary;
504ed0d50c3Schristos unsigned int shndx = psymval->input_shndx(&is_ordinary);
505ed0d50c3Schristos if ((shndx == elfcpp::SHN_UNDEF)
506ed0d50c3Schristos || (is_ordinary
507ed0d50c3Schristos && shndx != elfcpp::SHN_UNDEF
508ed0d50c3Schristos && !object->is_section_included(shndx)
509ed0d50c3Schristos && !this->symbol_table_->is_section_folded(object, shndx)))
510ed0d50c3Schristos {
511ed0d50c3Schristos gold_error(_("undefined or discarded local symbol %u from "
512ed0d50c3Schristos " object %s in GOT"),
513ed0d50c3Schristos reloc.index(), reloc.relobj()->name().c_str());
514ed0d50c3Schristos continue;
515ed0d50c3Schristos }
516ed0d50c3Schristos value = psymval->value(object, 0);
517ed0d50c3Schristos }
518ed0d50c3Schristos else
519ed0d50c3Schristos {
520ed0d50c3Schristos const Symbol* gsym = reloc.symbol();
521ed0d50c3Schristos gold_assert(gsym != NULL);
522ed0d50c3Schristos if (gsym->is_forwarder())
523ed0d50c3Schristos gsym = this->symbol_table_->resolve_forwards(gsym);
524ed0d50c3Schristos
525ed0d50c3Schristos // We are doing static linking. Issue an error and skip this
526ed0d50c3Schristos // relocation if the symbol is undefined or in a discarded_section
527ed0d50c3Schristos // unless it is a weakly_undefined symbol.
528ed0d50c3Schristos if ((gsym->is_defined_in_discarded_section()
529ed0d50c3Schristos || gsym->is_undefined())
530ed0d50c3Schristos && !gsym->is_weak_undefined())
531ed0d50c3Schristos {
532ed0d50c3Schristos gold_error(_("undefined or discarded symbol %s in GOT"),
533ed0d50c3Schristos gsym->name());
534ed0d50c3Schristos continue;
535ed0d50c3Schristos }
536ed0d50c3Schristos
537ed0d50c3Schristos if (!gsym->is_weak_undefined())
538ed0d50c3Schristos {
539ed0d50c3Schristos const Sized_symbol<size>* sym =
540ed0d50c3Schristos static_cast<const Sized_symbol<size>*>(gsym);
541ed0d50c3Schristos value = sym->value();
542ed0d50c3Schristos }
543ed0d50c3Schristos else
544ed0d50c3Schristos value = 0;
545ed0d50c3Schristos }
546ed0d50c3Schristos
547ed0d50c3Schristos unsigned got_offset = reloc.got_offset();
548ed0d50c3Schristos gold_assert(got_offset < oview_size);
549ed0d50c3Schristos
550ed0d50c3Schristos typedef typename elfcpp::Swap<size, big_endian>::Valtype Valtype;
551ed0d50c3Schristos Valtype* wv = reinterpret_cast<Valtype*>(oview + got_offset);
552ed0d50c3Schristos Valtype x;
553ed0d50c3Schristos switch (reloc.r_type())
554ed0d50c3Schristos {
555ed0d50c3Schristos case elfcpp::R_AARCH64_TLS_DTPREL64:
556ed0d50c3Schristos x = value;
557ed0d50c3Schristos break;
558ed0d50c3Schristos case elfcpp::R_AARCH64_TLS_TPREL64:
559ed0d50c3Schristos x = value + aligned_tcb_address;
560ed0d50c3Schristos break;
561ed0d50c3Schristos default:
562ed0d50c3Schristos gold_unreachable();
563ed0d50c3Schristos }
564ed0d50c3Schristos elfcpp::Swap<size, big_endian>::writeval(wv, x);
565ed0d50c3Schristos }
566ed0d50c3Schristos
567ed0d50c3Schristos of->write_output_view(offset, oview_size, oview);
568ed0d50c3Schristos }
569ed0d50c3Schristos
570ed0d50c3Schristos private:
571ed0d50c3Schristos // Symbol table of the output object.
572ed0d50c3Schristos Symbol_table* symbol_table_;
573ed0d50c3Schristos // A pointer to the Layout class, so that we can find the .dynamic
574ed0d50c3Schristos // section when we write out the GOT section.
575ed0d50c3Schristos Layout* layout_;
576ed0d50c3Schristos
577ed0d50c3Schristos // This class represent dynamic relocations that need to be applied by
578ed0d50c3Schristos // gold because we are using TLS relocations in a static link.
579ed0d50c3Schristos class Static_reloc
580ed0d50c3Schristos {
581ed0d50c3Schristos public:
Static_reloc(unsigned int got_offset,unsigned int r_type,Symbol * gsym)582ed0d50c3Schristos Static_reloc(unsigned int got_offset, unsigned int r_type, Symbol* gsym)
583ed0d50c3Schristos : got_offset_(got_offset), r_type_(r_type), symbol_is_global_(true)
584ed0d50c3Schristos { this->u_.global.symbol = gsym; }
585ed0d50c3Schristos
Static_reloc(unsigned int got_offset,unsigned int r_type,Sized_relobj_file<size,big_endian> * relobj,unsigned int index)586ed0d50c3Schristos Static_reloc(unsigned int got_offset, unsigned int r_type,
587ed0d50c3Schristos Sized_relobj_file<size, big_endian>* relobj, unsigned int index)
588ed0d50c3Schristos : got_offset_(got_offset), r_type_(r_type), symbol_is_global_(false)
589ed0d50c3Schristos {
590ed0d50c3Schristos this->u_.local.relobj = relobj;
591ed0d50c3Schristos this->u_.local.index = index;
592ed0d50c3Schristos }
593ed0d50c3Schristos
594ed0d50c3Schristos // Return the GOT offset.
595ed0d50c3Schristos unsigned int
got_offset() const596ed0d50c3Schristos got_offset() const
597ed0d50c3Schristos { return this->got_offset_; }
598ed0d50c3Schristos
599ed0d50c3Schristos // Relocation type.
600ed0d50c3Schristos unsigned int
r_type() const601ed0d50c3Schristos r_type() const
602ed0d50c3Schristos { return this->r_type_; }
603ed0d50c3Schristos
604ed0d50c3Schristos // Whether the symbol is global or not.
605ed0d50c3Schristos bool
symbol_is_global() const606ed0d50c3Schristos symbol_is_global() const
607ed0d50c3Schristos { return this->symbol_is_global_; }
608ed0d50c3Schristos
609ed0d50c3Schristos // For a relocation against a global symbol, the global symbol.
610ed0d50c3Schristos Symbol*
symbol() const611ed0d50c3Schristos symbol() const
612ed0d50c3Schristos {
613ed0d50c3Schristos gold_assert(this->symbol_is_global_);
614ed0d50c3Schristos return this->u_.global.symbol;
615ed0d50c3Schristos }
616ed0d50c3Schristos
617ed0d50c3Schristos // For a relocation against a local symbol, the defining object.
618ed0d50c3Schristos Sized_relobj_file<size, big_endian>*
relobj() const619ed0d50c3Schristos relobj() const
620ed0d50c3Schristos {
621ed0d50c3Schristos gold_assert(!this->symbol_is_global_);
622ed0d50c3Schristos return this->u_.local.relobj;
623ed0d50c3Schristos }
624ed0d50c3Schristos
625ed0d50c3Schristos // For a relocation against a local symbol, the local symbol index.
626ed0d50c3Schristos unsigned int
index() const627ed0d50c3Schristos index() const
628ed0d50c3Schristos {
629ed0d50c3Schristos gold_assert(!this->symbol_is_global_);
630ed0d50c3Schristos return this->u_.local.index;
631ed0d50c3Schristos }
632ed0d50c3Schristos
633ed0d50c3Schristos private:
634ed0d50c3Schristos // GOT offset of the entry to which this relocation is applied.
635ed0d50c3Schristos unsigned int got_offset_;
636ed0d50c3Schristos // Type of relocation.
637ed0d50c3Schristos unsigned int r_type_;
638ed0d50c3Schristos // Whether this relocation is against a global symbol.
639ed0d50c3Schristos bool symbol_is_global_;
640ed0d50c3Schristos // A global or local symbol.
641ed0d50c3Schristos union
642ed0d50c3Schristos {
643ed0d50c3Schristos struct
644ed0d50c3Schristos {
645ed0d50c3Schristos // For a global symbol, the symbol itself.
646ed0d50c3Schristos Symbol* symbol;
647ed0d50c3Schristos } global;
648ed0d50c3Schristos struct
649ed0d50c3Schristos {
650ed0d50c3Schristos // For a local symbol, the object defining the symbol.
651ed0d50c3Schristos Sized_relobj_file<size, big_endian>* relobj;
652ed0d50c3Schristos // For a local symbol, the symbol index.
653ed0d50c3Schristos unsigned int index;
654ed0d50c3Schristos } local;
655ed0d50c3Schristos } u_;
656ed0d50c3Schristos }; // End of inner class Static_reloc
657ed0d50c3Schristos
658ed0d50c3Schristos std::vector<Static_reloc> static_relocs_;
659ed0d50c3Schristos }; // End of Output_data_got_aarch64
660ed0d50c3Schristos
661ed0d50c3Schristos
662ed0d50c3Schristos template<int size, bool big_endian>
663ed0d50c3Schristos class AArch64_input_section;
664ed0d50c3Schristos
665ed0d50c3Schristos
666ed0d50c3Schristos template<int size, bool big_endian>
667ed0d50c3Schristos class AArch64_output_section;
668ed0d50c3Schristos
669ed0d50c3Schristos
670ed0d50c3Schristos template<int size, bool big_endian>
671ed0d50c3Schristos class AArch64_relobj;
672ed0d50c3Schristos
673ed0d50c3Schristos
674ed0d50c3Schristos // Stub type enum constants.
675ed0d50c3Schristos
676ed0d50c3Schristos enum
677ed0d50c3Schristos {
678ed0d50c3Schristos ST_NONE = 0,
679ed0d50c3Schristos
680ed0d50c3Schristos // Using adrp/add pair, 4 insns (including alignment) without mem access,
681ed0d50c3Schristos // the fastest stub. This has a limited jump distance, which is tested by
682ed0d50c3Schristos // aarch64_valid_for_adrp_p.
683ed0d50c3Schristos ST_ADRP_BRANCH = 1,
684ed0d50c3Schristos
685ed0d50c3Schristos // Using ldr-absolute-address/br-register, 4 insns with 1 mem access,
686ed0d50c3Schristos // unlimited in jump distance.
687ed0d50c3Schristos ST_LONG_BRANCH_ABS = 2,
688ed0d50c3Schristos
689ed0d50c3Schristos // Using ldr/calculate-pcrel/jump, 8 insns (including alignment) with 1
690ed0d50c3Schristos // mem access, slowest one. Only used in position independent executables.
691ed0d50c3Schristos ST_LONG_BRANCH_PCREL = 3,
692ed0d50c3Schristos
693ed0d50c3Schristos // Stub for erratum 843419 handling.
694ed0d50c3Schristos ST_E_843419 = 4,
695ed0d50c3Schristos
696ed0d50c3Schristos // Stub for erratum 835769 handling.
697ed0d50c3Schristos ST_E_835769 = 5,
698ed0d50c3Schristos
699ed0d50c3Schristos // Number of total stub types.
700ed0d50c3Schristos ST_NUMBER = 6
701ed0d50c3Schristos };
702ed0d50c3Schristos
703ed0d50c3Schristos
704ed0d50c3Schristos // Struct that wraps insns for a particular stub. All stub templates are
705ed0d50c3Schristos // created/initialized as constants by Stub_template_repertoire.
706ed0d50c3Schristos
707ed0d50c3Schristos template<bool big_endian>
708ed0d50c3Schristos struct Stub_template
709ed0d50c3Schristos {
710ed0d50c3Schristos const typename AArch64_insn_utilities<big_endian>::Insntype* insns;
711ed0d50c3Schristos const int insn_num;
712ed0d50c3Schristos };
713ed0d50c3Schristos
714ed0d50c3Schristos
715ed0d50c3Schristos // Simple singleton class that creates/initializes/stores all types of stub
716ed0d50c3Schristos // templates.
717ed0d50c3Schristos
718ed0d50c3Schristos template<bool big_endian>
719ed0d50c3Schristos class Stub_template_repertoire
720ed0d50c3Schristos {
721ed0d50c3Schristos public:
722ed0d50c3Schristos typedef typename AArch64_insn_utilities<big_endian>::Insntype Insntype;
723ed0d50c3Schristos
724ed0d50c3Schristos // Single static method to get stub template for a given stub type.
725ed0d50c3Schristos static const Stub_template<big_endian>*
get_stub_template(int type)726ed0d50c3Schristos get_stub_template(int type)
727ed0d50c3Schristos {
728ed0d50c3Schristos static Stub_template_repertoire<big_endian> singleton;
729ed0d50c3Schristos return singleton.stub_templates_[type];
730ed0d50c3Schristos }
731ed0d50c3Schristos
732ed0d50c3Schristos private:
733ed0d50c3Schristos // Constructor - creates/initializes all stub templates.
734ed0d50c3Schristos Stub_template_repertoire();
~Stub_template_repertoire()735ed0d50c3Schristos ~Stub_template_repertoire()
736ed0d50c3Schristos { }
737ed0d50c3Schristos
738ed0d50c3Schristos // Disallowing copy ctor and copy assignment operator.
739ed0d50c3Schristos Stub_template_repertoire(Stub_template_repertoire&);
740ed0d50c3Schristos Stub_template_repertoire& operator=(Stub_template_repertoire&);
741ed0d50c3Schristos
742ed0d50c3Schristos // Data that stores all insn templates.
743ed0d50c3Schristos const Stub_template<big_endian>* stub_templates_[ST_NUMBER];
744ed0d50c3Schristos }; // End of "class Stub_template_repertoire".
745ed0d50c3Schristos
746ed0d50c3Schristos
747ed0d50c3Schristos // Constructor - creates/initilizes all stub templates.
748ed0d50c3Schristos
749ed0d50c3Schristos template<bool big_endian>
Stub_template_repertoire()750ed0d50c3Schristos Stub_template_repertoire<big_endian>::Stub_template_repertoire()
751ed0d50c3Schristos {
752ed0d50c3Schristos // Insn array definitions.
753ed0d50c3Schristos const static Insntype ST_NONE_INSNS[] = {};
754ed0d50c3Schristos
755ed0d50c3Schristos const static Insntype ST_ADRP_BRANCH_INSNS[] =
756ed0d50c3Schristos {
757ed0d50c3Schristos 0x90000010, /* adrp ip0, X */
758ed0d50c3Schristos /* ADR_PREL_PG_HI21(X) */
759ed0d50c3Schristos 0x91000210, /* add ip0, ip0, :lo12:X */
760ed0d50c3Schristos /* ADD_ABS_LO12_NC(X) */
761ed0d50c3Schristos 0xd61f0200, /* br ip0 */
762ed0d50c3Schristos 0x00000000, /* alignment padding */
763ed0d50c3Schristos };
764ed0d50c3Schristos
765ed0d50c3Schristos const static Insntype ST_LONG_BRANCH_ABS_INSNS[] =
766ed0d50c3Schristos {
767ed0d50c3Schristos 0x58000050, /* ldr ip0, 0x8 */
768ed0d50c3Schristos 0xd61f0200, /* br ip0 */
769ed0d50c3Schristos 0x00000000, /* address field */
770ed0d50c3Schristos 0x00000000, /* address fields */
771ed0d50c3Schristos };
772ed0d50c3Schristos
773ed0d50c3Schristos const static Insntype ST_LONG_BRANCH_PCREL_INSNS[] =
774ed0d50c3Schristos {
775ed0d50c3Schristos 0x58000090, /* ldr ip0, 0x10 */
776ed0d50c3Schristos 0x10000011, /* adr ip1, #0 */
777ed0d50c3Schristos 0x8b110210, /* add ip0, ip0, ip1 */
778ed0d50c3Schristos 0xd61f0200, /* br ip0 */
779ed0d50c3Schristos 0x00000000, /* address field */
780ed0d50c3Schristos 0x00000000, /* address field */
781ed0d50c3Schristos 0x00000000, /* alignment padding */
782ed0d50c3Schristos 0x00000000, /* alignment padding */
783ed0d50c3Schristos };
784ed0d50c3Schristos
785ed0d50c3Schristos const static Insntype ST_E_843419_INSNS[] =
786ed0d50c3Schristos {
787ed0d50c3Schristos 0x00000000, /* Placeholder for erratum insn. */
788ed0d50c3Schristos 0x14000000, /* b <label> */
789ed0d50c3Schristos };
790ed0d50c3Schristos
79106324dcfSchristos // ST_E_835769 has the same stub template as ST_E_843419
79206324dcfSchristos // but we reproduce the array here so that the sizeof
79306324dcfSchristos // expressions in install_insn_template will work.
79406324dcfSchristos const static Insntype ST_E_835769_INSNS[] =
79506324dcfSchristos {
79606324dcfSchristos 0x00000000, /* Placeholder for erratum insn. */
79706324dcfSchristos 0x14000000, /* b <label> */
79806324dcfSchristos };
799ed0d50c3Schristos
800ed0d50c3Schristos #define install_insn_template(T) \
801ed0d50c3Schristos const static Stub_template<big_endian> template_##T = { \
802ed0d50c3Schristos T##_INSNS, sizeof(T##_INSNS) / sizeof(T##_INSNS[0]) }; \
803ed0d50c3Schristos this->stub_templates_[T] = &template_##T
804ed0d50c3Schristos
805ed0d50c3Schristos install_insn_template(ST_NONE);
806ed0d50c3Schristos install_insn_template(ST_ADRP_BRANCH);
807ed0d50c3Schristos install_insn_template(ST_LONG_BRANCH_ABS);
808ed0d50c3Schristos install_insn_template(ST_LONG_BRANCH_PCREL);
809ed0d50c3Schristos install_insn_template(ST_E_843419);
810ed0d50c3Schristos install_insn_template(ST_E_835769);
811ed0d50c3Schristos
812ed0d50c3Schristos #undef install_insn_template
813ed0d50c3Schristos }
814ed0d50c3Schristos
815ed0d50c3Schristos
816ed0d50c3Schristos // Base class for stubs.
817ed0d50c3Schristos
818ed0d50c3Schristos template<int size, bool big_endian>
819ed0d50c3Schristos class Stub_base
820ed0d50c3Schristos {
821ed0d50c3Schristos public:
822ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
823ed0d50c3Schristos typedef typename AArch64_insn_utilities<big_endian>::Insntype Insntype;
824ed0d50c3Schristos
825ed0d50c3Schristos static const AArch64_address invalid_address =
826ed0d50c3Schristos static_cast<AArch64_address>(-1);
827ed0d50c3Schristos
828ed0d50c3Schristos static const section_offset_type invalid_offset =
829ed0d50c3Schristos static_cast<section_offset_type>(-1);
830ed0d50c3Schristos
Stub_base(int type)831ed0d50c3Schristos Stub_base(int type)
832ed0d50c3Schristos : destination_address_(invalid_address),
833ed0d50c3Schristos offset_(invalid_offset),
834ed0d50c3Schristos type_(type)
835ed0d50c3Schristos {}
836ed0d50c3Schristos
~Stub_base()837ed0d50c3Schristos ~Stub_base()
838ed0d50c3Schristos {}
839ed0d50c3Schristos
840ed0d50c3Schristos // Get stub type.
841ed0d50c3Schristos int
type() const842ed0d50c3Schristos type() const
843ed0d50c3Schristos { return this->type_; }
844ed0d50c3Schristos
845ed0d50c3Schristos // Get stub template that provides stub insn information.
846ed0d50c3Schristos const Stub_template<big_endian>*
stub_template() const847ed0d50c3Schristos stub_template() const
848ed0d50c3Schristos {
849ed0d50c3Schristos return Stub_template_repertoire<big_endian>::
850ed0d50c3Schristos get_stub_template(this->type());
851ed0d50c3Schristos }
852ed0d50c3Schristos
853ed0d50c3Schristos // Get destination address.
854ed0d50c3Schristos AArch64_address
destination_address() const855ed0d50c3Schristos destination_address() const
856ed0d50c3Schristos {
857ed0d50c3Schristos gold_assert(this->destination_address_ != this->invalid_address);
858ed0d50c3Schristos return this->destination_address_;
859ed0d50c3Schristos }
860ed0d50c3Schristos
861ed0d50c3Schristos // Set destination address.
862ed0d50c3Schristos void
set_destination_address(AArch64_address address)863ed0d50c3Schristos set_destination_address(AArch64_address address)
864ed0d50c3Schristos {
865ed0d50c3Schristos gold_assert(address != this->invalid_address);
866ed0d50c3Schristos this->destination_address_ = address;
867ed0d50c3Schristos }
868ed0d50c3Schristos
869ed0d50c3Schristos // Reset the destination address.
870ed0d50c3Schristos void
reset_destination_address()871ed0d50c3Schristos reset_destination_address()
872ed0d50c3Schristos { this->destination_address_ = this->invalid_address; }
873ed0d50c3Schristos
874ed0d50c3Schristos // Get offset of code stub. For Reloc_stub, it is the offset from the
875ed0d50c3Schristos // beginning of its containing stub table; for Erratum_stub, it is the offset
876ed0d50c3Schristos // from the end of reloc_stubs.
877ed0d50c3Schristos section_offset_type
offset() const878ed0d50c3Schristos offset() const
879ed0d50c3Schristos {
880ed0d50c3Schristos gold_assert(this->offset_ != this->invalid_offset);
881ed0d50c3Schristos return this->offset_;
882ed0d50c3Schristos }
883ed0d50c3Schristos
884ed0d50c3Schristos // Set stub offset.
885ed0d50c3Schristos void
set_offset(section_offset_type offset)886ed0d50c3Schristos set_offset(section_offset_type offset)
887ed0d50c3Schristos { this->offset_ = offset; }
888ed0d50c3Schristos
889ed0d50c3Schristos // Return the stub insn.
890ed0d50c3Schristos const Insntype*
insns() const891ed0d50c3Schristos insns() const
892ed0d50c3Schristos { return this->stub_template()->insns; }
893ed0d50c3Schristos
894ed0d50c3Schristos // Return num of stub insns.
895ed0d50c3Schristos unsigned int
insn_num() const896ed0d50c3Schristos insn_num() const
897ed0d50c3Schristos { return this->stub_template()->insn_num; }
898ed0d50c3Schristos
899ed0d50c3Schristos // Get size of the stub.
900ed0d50c3Schristos int
stub_size() const901ed0d50c3Schristos stub_size() const
902ed0d50c3Schristos {
903ed0d50c3Schristos return this->insn_num() *
904ed0d50c3Schristos AArch64_insn_utilities<big_endian>::BYTES_PER_INSN;
905ed0d50c3Schristos }
906ed0d50c3Schristos
907ed0d50c3Schristos // Write stub to output file.
908ed0d50c3Schristos void
write(unsigned char * view,section_size_type view_size)909ed0d50c3Schristos write(unsigned char* view, section_size_type view_size)
910ed0d50c3Schristos { this->do_write(view, view_size); }
911ed0d50c3Schristos
912ed0d50c3Schristos protected:
913ed0d50c3Schristos // Abstract method to be implemented by sub-classes.
914ed0d50c3Schristos virtual void
915ed0d50c3Schristos do_write(unsigned char*, section_size_type) = 0;
916ed0d50c3Schristos
917ed0d50c3Schristos private:
918ed0d50c3Schristos // The last insn of a stub is a jump to destination insn. This field records
919ed0d50c3Schristos // the destination address.
920ed0d50c3Schristos AArch64_address destination_address_;
921ed0d50c3Schristos // The stub offset. Note this has difference interpretations between an
922ed0d50c3Schristos // Reloc_stub and an Erratum_stub. For Reloc_stub this is the offset from the
923ed0d50c3Schristos // beginning of the containing stub_table, whereas for Erratum_stub, this is
924ed0d50c3Schristos // the offset from the end of reloc_stubs.
925ed0d50c3Schristos section_offset_type offset_;
926ed0d50c3Schristos // Stub type.
927ed0d50c3Schristos const int type_;
928ed0d50c3Schristos }; // End of "Stub_base".
929ed0d50c3Schristos
930ed0d50c3Schristos
931ed0d50c3Schristos // Erratum stub class. An erratum stub differs from a reloc stub in that for
932ed0d50c3Schristos // each erratum occurrence, we generate an erratum stub. We never share erratum
93306324dcfSchristos // stubs, whereas for reloc stubs, different branch insns share a single reloc
934ed0d50c3Schristos // stub as long as the branch targets are the same. (More to the point, reloc
935ed0d50c3Schristos // stubs can be shared because they're used to reach a specific target, whereas
936ed0d50c3Schristos // erratum stubs branch back to the original control flow.)
937ed0d50c3Schristos
938ed0d50c3Schristos template<int size, bool big_endian>
939ed0d50c3Schristos class Erratum_stub : public Stub_base<size, big_endian>
940ed0d50c3Schristos {
941ed0d50c3Schristos public:
942ed0d50c3Schristos typedef AArch64_relobj<size, big_endian> The_aarch64_relobj;
943ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
944ed0d50c3Schristos typedef AArch64_insn_utilities<big_endian> Insn_utilities;
945ed0d50c3Schristos typedef typename AArch64_insn_utilities<big_endian>::Insntype Insntype;
946ed0d50c3Schristos
947ed0d50c3Schristos static const int STUB_ADDR_ALIGN;
948ed0d50c3Schristos
949ed0d50c3Schristos static const Insntype invalid_insn = static_cast<Insntype>(-1);
950ed0d50c3Schristos
Erratum_stub(The_aarch64_relobj * relobj,int type,unsigned shndx,unsigned int sh_offset)951ed0d50c3Schristos Erratum_stub(The_aarch64_relobj* relobj, int type,
952ed0d50c3Schristos unsigned shndx, unsigned int sh_offset)
953ed0d50c3Schristos : Stub_base<size, big_endian>(type), relobj_(relobj),
954ed0d50c3Schristos shndx_(shndx), sh_offset_(sh_offset),
955ed0d50c3Schristos erratum_insn_(invalid_insn),
956ed0d50c3Schristos erratum_address_(this->invalid_address)
957ed0d50c3Schristos {}
958ed0d50c3Schristos
~Erratum_stub()959ed0d50c3Schristos ~Erratum_stub() {}
960ed0d50c3Schristos
961ed0d50c3Schristos // Return the object that contains the erratum.
962ed0d50c3Schristos The_aarch64_relobj*
relobj()963ed0d50c3Schristos relobj()
964ed0d50c3Schristos { return this->relobj_; }
965ed0d50c3Schristos
966ed0d50c3Schristos // Get section index of the erratum.
967ed0d50c3Schristos unsigned int
shndx() const968ed0d50c3Schristos shndx() const
969ed0d50c3Schristos { return this->shndx_; }
970ed0d50c3Schristos
971ed0d50c3Schristos // Get section offset of the erratum.
972ed0d50c3Schristos unsigned int
sh_offset() const973ed0d50c3Schristos sh_offset() const
974ed0d50c3Schristos { return this->sh_offset_; }
975ed0d50c3Schristos
976ed0d50c3Schristos // Get the erratum insn. This is the insn located at erratum_insn_address.
977ed0d50c3Schristos Insntype
erratum_insn() const978ed0d50c3Schristos erratum_insn() const
979ed0d50c3Schristos {
980ed0d50c3Schristos gold_assert(this->erratum_insn_ != this->invalid_insn);
981ed0d50c3Schristos return this->erratum_insn_;
982ed0d50c3Schristos }
983ed0d50c3Schristos
984ed0d50c3Schristos // Set the insn that the erratum happens to.
985ed0d50c3Schristos void
set_erratum_insn(Insntype insn)986ed0d50c3Schristos set_erratum_insn(Insntype insn)
987ed0d50c3Schristos { this->erratum_insn_ = insn; }
988ed0d50c3Schristos
989ed0d50c3Schristos // For 843419, the erratum insn is ld/st xt, [xn, #uimm], which may be a
990ed0d50c3Schristos // relocation spot, in this case, the erratum_insn_ recorded at scanning phase
991ed0d50c3Schristos // is no longer the one we want to write out to the stub, update erratum_insn_
992ed0d50c3Schristos // with relocated version. Also note that in this case xn must not be "PC", so
993ed0d50c3Schristos // it is safe to move the erratum insn from the origin place to the stub. For
994ed0d50c3Schristos // 835769, the erratum insn is multiply-accumulate insn, which could not be a
995ed0d50c3Schristos // relocation spot (assertion added though).
996ed0d50c3Schristos void
update_erratum_insn(Insntype insn)997ed0d50c3Schristos update_erratum_insn(Insntype insn)
998ed0d50c3Schristos {
999ed0d50c3Schristos gold_assert(this->erratum_insn_ != this->invalid_insn);
1000ed0d50c3Schristos switch (this->type())
1001ed0d50c3Schristos {
1002ed0d50c3Schristos case ST_E_843419:
1003ed0d50c3Schristos gold_assert(Insn_utilities::aarch64_ldst_uimm(insn));
1004ed0d50c3Schristos gold_assert(Insn_utilities::aarch64_ldst_uimm(this->erratum_insn()));
1005ed0d50c3Schristos gold_assert(Insn_utilities::aarch64_rd(insn) ==
1006ed0d50c3Schristos Insn_utilities::aarch64_rd(this->erratum_insn()));
1007ed0d50c3Schristos gold_assert(Insn_utilities::aarch64_rn(insn) ==
1008ed0d50c3Schristos Insn_utilities::aarch64_rn(this->erratum_insn()));
1009ed0d50c3Schristos // Update plain ld/st insn with relocated insn.
1010ed0d50c3Schristos this->erratum_insn_ = insn;
1011ed0d50c3Schristos break;
1012ed0d50c3Schristos case ST_E_835769:
1013ed0d50c3Schristos gold_assert(insn == this->erratum_insn());
1014ed0d50c3Schristos break;
1015ed0d50c3Schristos default:
1016ed0d50c3Schristos gold_unreachable();
1017ed0d50c3Schristos }
1018ed0d50c3Schristos }
1019ed0d50c3Schristos
1020ed0d50c3Schristos
1021ed0d50c3Schristos // Return the address where an erratum must be done.
1022ed0d50c3Schristos AArch64_address
erratum_address() const1023ed0d50c3Schristos erratum_address() const
1024ed0d50c3Schristos {
1025ed0d50c3Schristos gold_assert(this->erratum_address_ != this->invalid_address);
1026ed0d50c3Schristos return this->erratum_address_;
1027ed0d50c3Schristos }
1028ed0d50c3Schristos
1029ed0d50c3Schristos // Set the address where an erratum must be done.
1030ed0d50c3Schristos void
set_erratum_address(AArch64_address addr)1031ed0d50c3Schristos set_erratum_address(AArch64_address addr)
1032ed0d50c3Schristos { this->erratum_address_ = addr; }
1033ed0d50c3Schristos
103406324dcfSchristos // Later relaxation passes of may alter the recorded erratum and destination
103506324dcfSchristos // address. Given an up to date output section address of shidx_ in
103606324dcfSchristos // relobj_ we can derive the erratum_address and destination address.
103706324dcfSchristos void
update_erratum_address(AArch64_address output_section_addr)103806324dcfSchristos update_erratum_address(AArch64_address output_section_addr)
103906324dcfSchristos {
104006324dcfSchristos const int BPI = AArch64_insn_utilities<big_endian>::BYTES_PER_INSN;
104106324dcfSchristos AArch64_address updated_addr = output_section_addr + this->sh_offset_;
104206324dcfSchristos this->set_erratum_address(updated_addr);
104306324dcfSchristos this->set_destination_address(updated_addr + BPI);
104406324dcfSchristos }
104506324dcfSchristos
1046ed0d50c3Schristos // Comparator used to group Erratum_stubs in a set by (obj, shndx,
104706324dcfSchristos // sh_offset). We do not include 'type' in the calculation, because there is
1048ed0d50c3Schristos // at most one stub type at (obj, shndx, sh_offset).
1049ed0d50c3Schristos bool
operator <(const Erratum_stub<size,big_endian> & k) const1050ed0d50c3Schristos operator<(const Erratum_stub<size, big_endian>& k) const
1051ed0d50c3Schristos {
1052ed0d50c3Schristos if (this == &k)
1053ed0d50c3Schristos return false;
1054ed0d50c3Schristos // We group stubs by relobj.
1055ed0d50c3Schristos if (this->relobj_ != k.relobj_)
1056ed0d50c3Schristos return this->relobj_ < k.relobj_;
1057ed0d50c3Schristos // Then by section index.
1058ed0d50c3Schristos if (this->shndx_ != k.shndx_)
1059ed0d50c3Schristos return this->shndx_ < k.shndx_;
1060ed0d50c3Schristos // Lastly by section offset.
1061ed0d50c3Schristos return this->sh_offset_ < k.sh_offset_;
1062ed0d50c3Schristos }
1063ed0d50c3Schristos
106406324dcfSchristos void
invalidate_erratum_stub()106506324dcfSchristos invalidate_erratum_stub()
106606324dcfSchristos {
106706324dcfSchristos gold_assert(this->erratum_insn_ != invalid_insn);
106806324dcfSchristos this->erratum_insn_ = invalid_insn;
106906324dcfSchristos }
107006324dcfSchristos
107106324dcfSchristos bool
is_invalidated_erratum_stub()107206324dcfSchristos is_invalidated_erratum_stub()
107306324dcfSchristos { return this->erratum_insn_ == invalid_insn; }
107406324dcfSchristos
1075ed0d50c3Schristos protected:
1076ed0d50c3Schristos virtual void
1077ed0d50c3Schristos do_write(unsigned char*, section_size_type);
1078ed0d50c3Schristos
1079ed0d50c3Schristos private:
1080ed0d50c3Schristos // The object that needs to be fixed.
1081ed0d50c3Schristos The_aarch64_relobj* relobj_;
1082ed0d50c3Schristos // The shndx in the object that needs to be fixed.
1083ed0d50c3Schristos const unsigned int shndx_;
1084ed0d50c3Schristos // The section offset in the obejct that needs to be fixed.
1085ed0d50c3Schristos const unsigned int sh_offset_;
1086ed0d50c3Schristos // The insn to be fixed.
1087ed0d50c3Schristos Insntype erratum_insn_;
1088ed0d50c3Schristos // The address of the above insn.
1089ed0d50c3Schristos AArch64_address erratum_address_;
1090ed0d50c3Schristos }; // End of "Erratum_stub".
1091ed0d50c3Schristos
1092ed0d50c3Schristos
1093ed0d50c3Schristos // Erratum sub class to wrap additional info needed by 843419. In fixing this
1094ed0d50c3Schristos // erratum, we may choose to replace 'adrp' with 'adr', in this case, we need
1095ed0d50c3Schristos // adrp's code position (two or three insns before erratum insn itself).
1096ed0d50c3Schristos
1097ed0d50c3Schristos template<int size, bool big_endian>
1098ed0d50c3Schristos class E843419_stub : public Erratum_stub<size, big_endian>
1099ed0d50c3Schristos {
1100ed0d50c3Schristos public:
1101ed0d50c3Schristos typedef typename AArch64_insn_utilities<big_endian>::Insntype Insntype;
1102ed0d50c3Schristos
E843419_stub(AArch64_relobj<size,big_endian> * relobj,unsigned int shndx,unsigned int sh_offset,unsigned int adrp_sh_offset)1103ed0d50c3Schristos E843419_stub(AArch64_relobj<size, big_endian>* relobj,
1104ed0d50c3Schristos unsigned int shndx, unsigned int sh_offset,
1105ed0d50c3Schristos unsigned int adrp_sh_offset)
1106ed0d50c3Schristos : Erratum_stub<size, big_endian>(relobj, ST_E_843419, shndx, sh_offset),
1107ed0d50c3Schristos adrp_sh_offset_(adrp_sh_offset)
1108ed0d50c3Schristos {}
1109ed0d50c3Schristos
1110ed0d50c3Schristos unsigned int
adrp_sh_offset() const1111ed0d50c3Schristos adrp_sh_offset() const
1112ed0d50c3Schristos { return this->adrp_sh_offset_; }
1113ed0d50c3Schristos
1114ed0d50c3Schristos private:
1115ed0d50c3Schristos // Section offset of "adrp". (We do not need a "adrp_shndx_" field, because we
111606324dcfSchristos // can obtain it from its parent.)
1117ed0d50c3Schristos const unsigned int adrp_sh_offset_;
1118ed0d50c3Schristos };
1119ed0d50c3Schristos
1120ed0d50c3Schristos
1121ed0d50c3Schristos template<int size, bool big_endian>
1122ed0d50c3Schristos const int Erratum_stub<size, big_endian>::STUB_ADDR_ALIGN = 4;
1123ed0d50c3Schristos
1124ed0d50c3Schristos // Comparator used in set definition.
1125ed0d50c3Schristos template<int size, bool big_endian>
1126ed0d50c3Schristos struct Erratum_stub_less
1127ed0d50c3Schristos {
1128ed0d50c3Schristos bool
operator ()__anond8ca3b600111::Erratum_stub_less1129ed0d50c3Schristos operator()(const Erratum_stub<size, big_endian>* s1,
1130ed0d50c3Schristos const Erratum_stub<size, big_endian>* s2) const
1131ed0d50c3Schristos { return *s1 < *s2; }
1132ed0d50c3Schristos };
1133ed0d50c3Schristos
1134ed0d50c3Schristos // Erratum_stub implementation for writing stub to output file.
1135ed0d50c3Schristos
1136ed0d50c3Schristos template<int size, bool big_endian>
1137ed0d50c3Schristos void
do_write(unsigned char * view,section_size_type)1138ed0d50c3Schristos Erratum_stub<size, big_endian>::do_write(unsigned char* view, section_size_type)
1139ed0d50c3Schristos {
1140ed0d50c3Schristos typedef typename elfcpp::Swap<32, big_endian>::Valtype Insntype;
1141ed0d50c3Schristos const Insntype* insns = this->insns();
1142ed0d50c3Schristos uint32_t num_insns = this->insn_num();
1143ed0d50c3Schristos Insntype* ip = reinterpret_cast<Insntype*>(view);
1144ed0d50c3Schristos // For current implemented erratum 843419 and 835769, the first insn in the
1145ed0d50c3Schristos // stub is always a copy of the problematic insn (in 843419, the mem access
1146ed0d50c3Schristos // insn, in 835769, the mac insn), followed by a jump-back.
1147ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(ip, this->erratum_insn());
1148ed0d50c3Schristos for (uint32_t i = 1; i < num_insns; ++i)
1149ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(ip + i, insns[i]);
1150ed0d50c3Schristos }
1151ed0d50c3Schristos
1152ed0d50c3Schristos
1153ed0d50c3Schristos // Reloc stub class.
1154ed0d50c3Schristos
1155ed0d50c3Schristos template<int size, bool big_endian>
1156ed0d50c3Schristos class Reloc_stub : public Stub_base<size, big_endian>
1157ed0d50c3Schristos {
1158ed0d50c3Schristos public:
1159ed0d50c3Schristos typedef Reloc_stub<size, big_endian> This;
1160ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
1161ed0d50c3Schristos
1162ed0d50c3Schristos // Branch range. This is used to calculate the section group size, as well as
1163ed0d50c3Schristos // determine whether a stub is needed.
1164ed0d50c3Schristos static const int MAX_BRANCH_OFFSET = ((1 << 25) - 1) << 2;
1165ed0d50c3Schristos static const int MIN_BRANCH_OFFSET = -((1 << 25) << 2);
1166ed0d50c3Schristos
1167ed0d50c3Schristos // Constant used to determine if an offset fits in the adrp instruction
1168ed0d50c3Schristos // encoding.
1169ed0d50c3Schristos static const int MAX_ADRP_IMM = (1 << 20) - 1;
1170ed0d50c3Schristos static const int MIN_ADRP_IMM = -(1 << 20);
1171ed0d50c3Schristos
1172ed0d50c3Schristos static const int BYTES_PER_INSN = 4;
1173ed0d50c3Schristos static const int STUB_ADDR_ALIGN;
1174ed0d50c3Schristos
1175ed0d50c3Schristos // Determine whether the offset fits in the jump/branch instruction.
1176ed0d50c3Schristos static bool
aarch64_valid_branch_offset_p(int64_t offset)1177ed0d50c3Schristos aarch64_valid_branch_offset_p(int64_t offset)
1178ed0d50c3Schristos { return offset >= MIN_BRANCH_OFFSET && offset <= MAX_BRANCH_OFFSET; }
1179ed0d50c3Schristos
1180ed0d50c3Schristos // Determine whether the offset fits in the adrp immediate field.
1181ed0d50c3Schristos static bool
aarch64_valid_for_adrp_p(AArch64_address location,AArch64_address dest)1182ed0d50c3Schristos aarch64_valid_for_adrp_p(AArch64_address location, AArch64_address dest)
1183ed0d50c3Schristos {
1184ed0d50c3Schristos typedef AArch64_relocate_functions<size, big_endian> Reloc;
1185ed0d50c3Schristos int64_t adrp_imm = (Reloc::Page(dest) - Reloc::Page(location)) >> 12;
1186ed0d50c3Schristos return adrp_imm >= MIN_ADRP_IMM && adrp_imm <= MAX_ADRP_IMM;
1187ed0d50c3Schristos }
1188ed0d50c3Schristos
1189ed0d50c3Schristos // Determine the stub type for a certain relocation or ST_NONE, if no stub is
1190ed0d50c3Schristos // needed.
1191ed0d50c3Schristos static int
1192ed0d50c3Schristos stub_type_for_reloc(unsigned int r_type, AArch64_address address,
1193ed0d50c3Schristos AArch64_address target);
1194ed0d50c3Schristos
Reloc_stub(int type)1195ed0d50c3Schristos Reloc_stub(int type)
1196ed0d50c3Schristos : Stub_base<size, big_endian>(type)
1197ed0d50c3Schristos { }
1198ed0d50c3Schristos
~Reloc_stub()1199ed0d50c3Schristos ~Reloc_stub()
1200ed0d50c3Schristos { }
1201ed0d50c3Schristos
1202ed0d50c3Schristos // The key class used to index the stub instance in the stub table's stub map.
1203ed0d50c3Schristos class Key
1204ed0d50c3Schristos {
1205ed0d50c3Schristos public:
Key(int type,const Symbol * symbol,const Relobj * relobj,unsigned int r_sym,int32_t addend)1206ed0d50c3Schristos Key(int type, const Symbol* symbol, const Relobj* relobj,
1207ed0d50c3Schristos unsigned int r_sym, int32_t addend)
1208ed0d50c3Schristos : type_(type), addend_(addend)
1209ed0d50c3Schristos {
1210ed0d50c3Schristos if (symbol != NULL)
1211ed0d50c3Schristos {
1212ed0d50c3Schristos this->r_sym_ = Reloc_stub::invalid_index;
1213ed0d50c3Schristos this->u_.symbol = symbol;
1214ed0d50c3Schristos }
1215ed0d50c3Schristos else
1216ed0d50c3Schristos {
1217ed0d50c3Schristos gold_assert(relobj != NULL && r_sym != invalid_index);
1218ed0d50c3Schristos this->r_sym_ = r_sym;
1219ed0d50c3Schristos this->u_.relobj = relobj;
1220ed0d50c3Schristos }
1221ed0d50c3Schristos }
1222ed0d50c3Schristos
~Key()1223ed0d50c3Schristos ~Key()
1224ed0d50c3Schristos { }
1225ed0d50c3Schristos
1226ed0d50c3Schristos // Return stub type.
1227ed0d50c3Schristos int
type() const1228ed0d50c3Schristos type() const
1229ed0d50c3Schristos { return this->type_; }
1230ed0d50c3Schristos
1231ed0d50c3Schristos // Return the local symbol index or invalid_index.
1232ed0d50c3Schristos unsigned int
r_sym() const1233ed0d50c3Schristos r_sym() const
1234ed0d50c3Schristos { return this->r_sym_; }
1235ed0d50c3Schristos
1236ed0d50c3Schristos // Return the symbol if there is one.
1237ed0d50c3Schristos const Symbol*
symbol() const1238ed0d50c3Schristos symbol() const
1239ed0d50c3Schristos { return this->r_sym_ == invalid_index ? this->u_.symbol : NULL; }
1240ed0d50c3Schristos
1241ed0d50c3Schristos // Return the relobj if there is one.
1242ed0d50c3Schristos const Relobj*
relobj() const1243ed0d50c3Schristos relobj() const
1244ed0d50c3Schristos { return this->r_sym_ != invalid_index ? this->u_.relobj : NULL; }
1245ed0d50c3Schristos
1246ed0d50c3Schristos // Whether this equals to another key k.
1247ed0d50c3Schristos bool
eq(const Key & k) const1248ed0d50c3Schristos eq(const Key& k) const
1249ed0d50c3Schristos {
1250ed0d50c3Schristos return ((this->type_ == k.type_)
1251ed0d50c3Schristos && (this->r_sym_ == k.r_sym_)
1252ed0d50c3Schristos && ((this->r_sym_ != Reloc_stub::invalid_index)
1253ed0d50c3Schristos ? (this->u_.relobj == k.u_.relobj)
1254ed0d50c3Schristos : (this->u_.symbol == k.u_.symbol))
1255ed0d50c3Schristos && (this->addend_ == k.addend_));
1256ed0d50c3Schristos }
1257ed0d50c3Schristos
1258ed0d50c3Schristos // Return a hash value.
1259ed0d50c3Schristos size_t
hash_value() const1260ed0d50c3Schristos hash_value() const
1261ed0d50c3Schristos {
1262ed0d50c3Schristos size_t name_hash_value = gold::string_hash<char>(
1263ed0d50c3Schristos (this->r_sym_ != Reloc_stub::invalid_index)
1264ed0d50c3Schristos ? this->u_.relobj->name().c_str()
1265ed0d50c3Schristos : this->u_.symbol->name());
1266ed0d50c3Schristos // We only have 4 stub types.
1267ed0d50c3Schristos size_t stub_type_hash_value = 0x03 & this->type_;
1268ed0d50c3Schristos return (name_hash_value
1269ed0d50c3Schristos ^ stub_type_hash_value
1270ed0d50c3Schristos ^ ((this->r_sym_ & 0x3fff) << 2)
1271ed0d50c3Schristos ^ ((this->addend_ & 0xffff) << 16));
1272ed0d50c3Schristos }
1273ed0d50c3Schristos
1274ed0d50c3Schristos // Functors for STL associative containers.
1275ed0d50c3Schristos struct hash
1276ed0d50c3Schristos {
1277ed0d50c3Schristos size_t
operator ()__anond8ca3b600111::Reloc_stub::Key::hash1278ed0d50c3Schristos operator()(const Key& k) const
1279ed0d50c3Schristos { return k.hash_value(); }
1280ed0d50c3Schristos };
1281ed0d50c3Schristos
1282ed0d50c3Schristos struct equal_to
1283ed0d50c3Schristos {
1284ed0d50c3Schristos bool
operator ()__anond8ca3b600111::Reloc_stub::Key::equal_to1285ed0d50c3Schristos operator()(const Key& k1, const Key& k2) const
1286ed0d50c3Schristos { return k1.eq(k2); }
1287ed0d50c3Schristos };
1288ed0d50c3Schristos
1289ed0d50c3Schristos private:
1290ed0d50c3Schristos // Stub type.
1291ed0d50c3Schristos const int type_;
1292ed0d50c3Schristos // If this is a local symbol, this is the index in the defining object.
1293ed0d50c3Schristos // Otherwise, it is invalid_index for a global symbol.
1294ed0d50c3Schristos unsigned int r_sym_;
1295ed0d50c3Schristos // If r_sym_ is an invalid index, this points to a global symbol.
1296ed0d50c3Schristos // Otherwise, it points to a relobj. We used the unsized and target
1297ed0d50c3Schristos // independent Symbol and Relobj classes instead of Sized_symbol<32> and
1298ed0d50c3Schristos // Arm_relobj, in order to avoid making the stub class a template
1299ed0d50c3Schristos // as most of the stub machinery is endianness-neutral. However, it
1300ed0d50c3Schristos // may require a bit of casting done by users of this class.
1301ed0d50c3Schristos union
1302ed0d50c3Schristos {
1303ed0d50c3Schristos const Symbol* symbol;
1304ed0d50c3Schristos const Relobj* relobj;
1305ed0d50c3Schristos } u_;
1306ed0d50c3Schristos // Addend associated with a reloc.
1307ed0d50c3Schristos int32_t addend_;
1308ed0d50c3Schristos }; // End of inner class Reloc_stub::Key
1309ed0d50c3Schristos
1310ed0d50c3Schristos protected:
1311ed0d50c3Schristos // This may be overridden in the child class.
1312ed0d50c3Schristos virtual void
1313ed0d50c3Schristos do_write(unsigned char*, section_size_type);
1314ed0d50c3Schristos
1315ed0d50c3Schristos private:
1316ed0d50c3Schristos static const unsigned int invalid_index = static_cast<unsigned int>(-1);
1317ed0d50c3Schristos }; // End of Reloc_stub
1318ed0d50c3Schristos
1319ed0d50c3Schristos template<int size, bool big_endian>
1320ed0d50c3Schristos const int Reloc_stub<size, big_endian>::STUB_ADDR_ALIGN = 4;
1321ed0d50c3Schristos
1322ed0d50c3Schristos // Write data to output file.
1323ed0d50c3Schristos
1324ed0d50c3Schristos template<int size, bool big_endian>
1325ed0d50c3Schristos void
1326ed0d50c3Schristos Reloc_stub<size, big_endian>::
do_write(unsigned char * view,section_size_type)1327ed0d50c3Schristos do_write(unsigned char* view, section_size_type)
1328ed0d50c3Schristos {
1329ed0d50c3Schristos typedef typename elfcpp::Swap<32, big_endian>::Valtype Insntype;
1330ed0d50c3Schristos const uint32_t* insns = this->insns();
1331ed0d50c3Schristos uint32_t num_insns = this->insn_num();
1332ed0d50c3Schristos Insntype* ip = reinterpret_cast<Insntype*>(view);
1333ed0d50c3Schristos for (uint32_t i = 0; i < num_insns; ++i)
1334ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(ip + i, insns[i]);
1335ed0d50c3Schristos }
1336ed0d50c3Schristos
1337ed0d50c3Schristos
1338ed0d50c3Schristos // Determine the stub type for a certain relocation or ST_NONE, if no stub is
1339ed0d50c3Schristos // needed.
1340ed0d50c3Schristos
1341ed0d50c3Schristos template<int size, bool big_endian>
1342ed0d50c3Schristos inline int
stub_type_for_reloc(unsigned int r_type,AArch64_address location,AArch64_address dest)1343ed0d50c3Schristos Reloc_stub<size, big_endian>::stub_type_for_reloc(
1344ed0d50c3Schristos unsigned int r_type, AArch64_address location, AArch64_address dest)
1345ed0d50c3Schristos {
1346ed0d50c3Schristos int64_t branch_offset = 0;
1347ed0d50c3Schristos switch(r_type)
1348ed0d50c3Schristos {
1349ed0d50c3Schristos case elfcpp::R_AARCH64_CALL26:
1350ed0d50c3Schristos case elfcpp::R_AARCH64_JUMP26:
1351ed0d50c3Schristos branch_offset = dest - location;
1352ed0d50c3Schristos break;
1353ed0d50c3Schristos default:
1354ed0d50c3Schristos gold_unreachable();
1355ed0d50c3Schristos }
1356ed0d50c3Schristos
1357ed0d50c3Schristos if (aarch64_valid_branch_offset_p(branch_offset))
1358ed0d50c3Schristos return ST_NONE;
1359ed0d50c3Schristos
1360ed0d50c3Schristos if (aarch64_valid_for_adrp_p(location, dest))
1361ed0d50c3Schristos return ST_ADRP_BRANCH;
1362ed0d50c3Schristos
1363ed0d50c3Schristos // Always use PC-relative addressing in case of -shared or -pie.
1364ed0d50c3Schristos if (parameters->options().output_is_position_independent())
1365ed0d50c3Schristos return ST_LONG_BRANCH_PCREL;
1366ed0d50c3Schristos
1367ed0d50c3Schristos // This saves 2 insns per stub, compared to ST_LONG_BRANCH_PCREL.
1368ed0d50c3Schristos // But is only applicable to non-shared or non-pie.
1369ed0d50c3Schristos return ST_LONG_BRANCH_ABS;
1370ed0d50c3Schristos }
1371ed0d50c3Schristos
137206324dcfSchristos // A class to hold stubs for the ARM target. This contains 2 different types of
137306324dcfSchristos // stubs - reloc stubs and erratum stubs.
1374ed0d50c3Schristos
1375ed0d50c3Schristos template<int size, bool big_endian>
1376ed0d50c3Schristos class Stub_table : public Output_data
1377ed0d50c3Schristos {
1378ed0d50c3Schristos public:
1379ed0d50c3Schristos typedef Target_aarch64<size, big_endian> The_target_aarch64;
1380ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
1381ed0d50c3Schristos typedef AArch64_relobj<size, big_endian> The_aarch64_relobj;
1382ed0d50c3Schristos typedef AArch64_input_section<size, big_endian> The_aarch64_input_section;
1383ed0d50c3Schristos typedef Reloc_stub<size, big_endian> The_reloc_stub;
1384ed0d50c3Schristos typedef typename The_reloc_stub::Key The_reloc_stub_key;
1385ed0d50c3Schristos typedef Erratum_stub<size, big_endian> The_erratum_stub;
1386ed0d50c3Schristos typedef Erratum_stub_less<size, big_endian> The_erratum_stub_less;
1387ed0d50c3Schristos typedef typename The_reloc_stub_key::hash The_reloc_stub_key_hash;
1388ed0d50c3Schristos typedef typename The_reloc_stub_key::equal_to The_reloc_stub_key_equal_to;
1389ed0d50c3Schristos typedef Stub_table<size, big_endian> The_stub_table;
1390ed0d50c3Schristos typedef Unordered_map<The_reloc_stub_key, The_reloc_stub*,
1391ed0d50c3Schristos The_reloc_stub_key_hash, The_reloc_stub_key_equal_to>
1392ed0d50c3Schristos Reloc_stub_map;
1393ed0d50c3Schristos typedef typename Reloc_stub_map::const_iterator Reloc_stub_map_const_iter;
1394ed0d50c3Schristos typedef Relocate_info<size, big_endian> The_relocate_info;
1395ed0d50c3Schristos
1396ed0d50c3Schristos typedef std::set<The_erratum_stub*, The_erratum_stub_less> Erratum_stub_set;
1397ed0d50c3Schristos typedef typename Erratum_stub_set::iterator Erratum_stub_set_iter;
1398ed0d50c3Schristos
Stub_table(The_aarch64_input_section * owner)1399ed0d50c3Schristos Stub_table(The_aarch64_input_section* owner)
1400ed0d50c3Schristos : Output_data(), owner_(owner), reloc_stubs_size_(0),
1401ed0d50c3Schristos erratum_stubs_size_(0), prev_data_size_(0)
1402ed0d50c3Schristos { }
1403ed0d50c3Schristos
~Stub_table()1404ed0d50c3Schristos ~Stub_table()
1405ed0d50c3Schristos { }
1406ed0d50c3Schristos
1407ed0d50c3Schristos The_aarch64_input_section*
owner() const1408ed0d50c3Schristos owner() const
1409ed0d50c3Schristos { return owner_; }
1410ed0d50c3Schristos
1411ed0d50c3Schristos // Whether this stub table is empty.
1412ed0d50c3Schristos bool
empty() const1413ed0d50c3Schristos empty() const
1414ed0d50c3Schristos { return reloc_stubs_.empty() && erratum_stubs_.empty(); }
1415ed0d50c3Schristos
1416ed0d50c3Schristos // Return the current data size.
1417ed0d50c3Schristos off_t
current_data_size() const1418ed0d50c3Schristos current_data_size() const
1419ed0d50c3Schristos { return this->current_data_size_for_child(); }
1420ed0d50c3Schristos
1421ed0d50c3Schristos // Add a STUB using KEY. The caller is responsible for avoiding addition
1422ed0d50c3Schristos // if a STUB with the same key has already been added.
1423ed0d50c3Schristos void
1424ed0d50c3Schristos add_reloc_stub(The_reloc_stub* stub, const The_reloc_stub_key& key);
1425ed0d50c3Schristos
1426ed0d50c3Schristos // Add an erratum stub into the erratum stub set. The set is ordered by
1427ed0d50c3Schristos // (relobj, shndx, sh_offset).
1428ed0d50c3Schristos void
1429ed0d50c3Schristos add_erratum_stub(The_erratum_stub* stub);
1430ed0d50c3Schristos
1431ed0d50c3Schristos // Find if such erratum exists for any given (obj, shndx, sh_offset).
1432ed0d50c3Schristos The_erratum_stub*
1433ed0d50c3Schristos find_erratum_stub(The_aarch64_relobj* a64relobj,
1434ed0d50c3Schristos unsigned int shndx, unsigned int sh_offset);
1435ed0d50c3Schristos
1436ed0d50c3Schristos // Find all the erratums for a given input section. The return value is a pair
1437ed0d50c3Schristos // of iterators [begin, end).
1438ed0d50c3Schristos std::pair<Erratum_stub_set_iter, Erratum_stub_set_iter>
1439ed0d50c3Schristos find_erratum_stubs_for_input_section(The_aarch64_relobj* a64relobj,
1440ed0d50c3Schristos unsigned int shndx);
1441ed0d50c3Schristos
1442ed0d50c3Schristos // Compute the erratum stub address.
1443ed0d50c3Schristos AArch64_address
erratum_stub_address(The_erratum_stub * stub) const1444ed0d50c3Schristos erratum_stub_address(The_erratum_stub* stub) const
1445ed0d50c3Schristos {
1446ed0d50c3Schristos AArch64_address r = align_address(this->address() + this->reloc_stubs_size_,
1447ed0d50c3Schristos The_erratum_stub::STUB_ADDR_ALIGN);
1448ed0d50c3Schristos r += stub->offset();
1449ed0d50c3Schristos return r;
1450ed0d50c3Schristos }
1451ed0d50c3Schristos
1452ed0d50c3Schristos // Finalize stubs. No-op here, just for completeness.
1453ed0d50c3Schristos void
finalize_stubs()1454ed0d50c3Schristos finalize_stubs()
1455ed0d50c3Schristos { }
1456ed0d50c3Schristos
1457ed0d50c3Schristos // Look up a relocation stub using KEY. Return NULL if there is none.
1458ed0d50c3Schristos The_reloc_stub*
find_reloc_stub(The_reloc_stub_key & key)1459ed0d50c3Schristos find_reloc_stub(The_reloc_stub_key& key)
1460ed0d50c3Schristos {
1461ed0d50c3Schristos Reloc_stub_map_const_iter p = this->reloc_stubs_.find(key);
1462ed0d50c3Schristos return (p != this->reloc_stubs_.end()) ? p->second : NULL;
1463ed0d50c3Schristos }
1464ed0d50c3Schristos
146506324dcfSchristos // Relocate reloc stubs in this stub table. This does not relocate erratum stubs.
1466ed0d50c3Schristos void
146706324dcfSchristos relocate_reloc_stubs(const The_relocate_info*,
1468ed0d50c3Schristos The_target_aarch64*,
1469ed0d50c3Schristos Output_section*,
1470ed0d50c3Schristos unsigned char*,
1471ed0d50c3Schristos AArch64_address,
1472ed0d50c3Schristos section_size_type);
1473ed0d50c3Schristos
147406324dcfSchristos // Relocate an erratum stub.
147506324dcfSchristos void
147606324dcfSchristos relocate_erratum_stub(The_erratum_stub*, unsigned char*);
147706324dcfSchristos
1478ed0d50c3Schristos // Update data size at the end of a relaxation pass. Return true if data size
1479ed0d50c3Schristos // is different from that of the previous relaxation pass.
1480ed0d50c3Schristos bool
update_data_size_changed_p()1481ed0d50c3Schristos update_data_size_changed_p()
1482ed0d50c3Schristos {
1483ed0d50c3Schristos // No addralign changed here.
1484ed0d50c3Schristos off_t s = align_address(this->reloc_stubs_size_,
1485ed0d50c3Schristos The_erratum_stub::STUB_ADDR_ALIGN)
1486ed0d50c3Schristos + this->erratum_stubs_size_;
1487ed0d50c3Schristos bool changed = (s != this->prev_data_size_);
1488ed0d50c3Schristos this->prev_data_size_ = s;
1489ed0d50c3Schristos return changed;
1490ed0d50c3Schristos }
1491ed0d50c3Schristos
1492ed0d50c3Schristos protected:
1493ed0d50c3Schristos // Write out section contents.
1494ed0d50c3Schristos void
1495ed0d50c3Schristos do_write(Output_file*);
1496ed0d50c3Schristos
1497ed0d50c3Schristos // Return the required alignment.
1498ed0d50c3Schristos uint64_t
do_addralign() const1499ed0d50c3Schristos do_addralign() const
1500ed0d50c3Schristos {
1501ed0d50c3Schristos return std::max(The_reloc_stub::STUB_ADDR_ALIGN,
1502ed0d50c3Schristos The_erratum_stub::STUB_ADDR_ALIGN);
1503ed0d50c3Schristos }
1504ed0d50c3Schristos
1505ed0d50c3Schristos // Reset address and file offset.
1506ed0d50c3Schristos void
do_reset_address_and_file_offset()1507ed0d50c3Schristos do_reset_address_and_file_offset()
1508ed0d50c3Schristos { this->set_current_data_size_for_child(this->prev_data_size_); }
1509ed0d50c3Schristos
1510ed0d50c3Schristos // Set final data size.
1511ed0d50c3Schristos void
set_final_data_size()1512ed0d50c3Schristos set_final_data_size()
1513ed0d50c3Schristos { this->set_data_size(this->current_data_size()); }
1514ed0d50c3Schristos
1515ed0d50c3Schristos private:
151606324dcfSchristos // Relocate one reloc stub.
1517ed0d50c3Schristos void
151806324dcfSchristos relocate_reloc_stub(The_reloc_stub*,
1519ed0d50c3Schristos const The_relocate_info*,
1520ed0d50c3Schristos The_target_aarch64*,
1521ed0d50c3Schristos Output_section*,
1522ed0d50c3Schristos unsigned char*,
1523ed0d50c3Schristos AArch64_address,
1524ed0d50c3Schristos section_size_type);
1525ed0d50c3Schristos
1526ed0d50c3Schristos private:
1527ed0d50c3Schristos // Owner of this stub table.
1528ed0d50c3Schristos The_aarch64_input_section* owner_;
1529ed0d50c3Schristos // The relocation stubs.
1530ed0d50c3Schristos Reloc_stub_map reloc_stubs_;
1531ed0d50c3Schristos // The erratum stubs.
1532ed0d50c3Schristos Erratum_stub_set erratum_stubs_;
1533ed0d50c3Schristos // Size of reloc stubs.
1534ed0d50c3Schristos off_t reloc_stubs_size_;
1535ed0d50c3Schristos // Size of erratum stubs.
1536ed0d50c3Schristos off_t erratum_stubs_size_;
1537ed0d50c3Schristos // data size of this in the previous pass.
1538ed0d50c3Schristos off_t prev_data_size_;
1539ed0d50c3Schristos }; // End of Stub_table
1540ed0d50c3Schristos
1541ed0d50c3Schristos
1542ed0d50c3Schristos // Add an erratum stub into the erratum stub set. The set is ordered by
1543ed0d50c3Schristos // (relobj, shndx, sh_offset).
1544ed0d50c3Schristos
1545ed0d50c3Schristos template<int size, bool big_endian>
1546ed0d50c3Schristos void
add_erratum_stub(The_erratum_stub * stub)1547ed0d50c3Schristos Stub_table<size, big_endian>::add_erratum_stub(The_erratum_stub* stub)
1548ed0d50c3Schristos {
1549ed0d50c3Schristos std::pair<Erratum_stub_set_iter, bool> ret =
1550ed0d50c3Schristos this->erratum_stubs_.insert(stub);
1551ed0d50c3Schristos gold_assert(ret.second);
1552ed0d50c3Schristos this->erratum_stubs_size_ = align_address(
1553ed0d50c3Schristos this->erratum_stubs_size_, The_erratum_stub::STUB_ADDR_ALIGN);
1554ed0d50c3Schristos stub->set_offset(this->erratum_stubs_size_);
1555ed0d50c3Schristos this->erratum_stubs_size_ += stub->stub_size();
1556ed0d50c3Schristos }
1557ed0d50c3Schristos
1558ed0d50c3Schristos
1559ed0d50c3Schristos // Find if such erratum exists for given (obj, shndx, sh_offset).
1560ed0d50c3Schristos
1561ed0d50c3Schristos template<int size, bool big_endian>
1562ed0d50c3Schristos Erratum_stub<size, big_endian>*
find_erratum_stub(The_aarch64_relobj * a64relobj,unsigned int shndx,unsigned int sh_offset)1563ed0d50c3Schristos Stub_table<size, big_endian>::find_erratum_stub(
1564ed0d50c3Schristos The_aarch64_relobj* a64relobj, unsigned int shndx, unsigned int sh_offset)
1565ed0d50c3Schristos {
1566ed0d50c3Schristos // A dummy object used as key to search in the set.
1567ed0d50c3Schristos The_erratum_stub key(a64relobj, ST_NONE,
1568ed0d50c3Schristos shndx, sh_offset);
1569ed0d50c3Schristos Erratum_stub_set_iter i = this->erratum_stubs_.find(&key);
1570ed0d50c3Schristos if (i != this->erratum_stubs_.end())
1571ed0d50c3Schristos {
1572ed0d50c3Schristos The_erratum_stub* stub(*i);
1573ed0d50c3Schristos gold_assert(stub->erratum_insn() != 0);
1574ed0d50c3Schristos return stub;
1575ed0d50c3Schristos }
1576ed0d50c3Schristos return NULL;
1577ed0d50c3Schristos }
1578ed0d50c3Schristos
1579ed0d50c3Schristos
1580ed0d50c3Schristos // Find all the errata for a given input section. The return value is a pair of
1581ed0d50c3Schristos // iterators [begin, end).
1582ed0d50c3Schristos
1583ed0d50c3Schristos template<int size, bool big_endian>
1584ed0d50c3Schristos std::pair<typename Stub_table<size, big_endian>::Erratum_stub_set_iter,
1585ed0d50c3Schristos typename Stub_table<size, big_endian>::Erratum_stub_set_iter>
find_erratum_stubs_for_input_section(The_aarch64_relobj * a64relobj,unsigned int shndx)1586ed0d50c3Schristos Stub_table<size, big_endian>::find_erratum_stubs_for_input_section(
1587ed0d50c3Schristos The_aarch64_relobj* a64relobj, unsigned int shndx)
1588ed0d50c3Schristos {
1589ed0d50c3Schristos typedef std::pair<Erratum_stub_set_iter, Erratum_stub_set_iter> Result_pair;
1590ed0d50c3Schristos Erratum_stub_set_iter start, end;
1591ed0d50c3Schristos The_erratum_stub low_key(a64relobj, ST_NONE, shndx, 0);
1592ed0d50c3Schristos start = this->erratum_stubs_.lower_bound(&low_key);
1593ed0d50c3Schristos if (start == this->erratum_stubs_.end())
1594ed0d50c3Schristos return Result_pair(this->erratum_stubs_.end(),
1595ed0d50c3Schristos this->erratum_stubs_.end());
1596ed0d50c3Schristos end = start;
1597ed0d50c3Schristos while (end != this->erratum_stubs_.end() &&
1598ed0d50c3Schristos (*end)->relobj() == a64relobj && (*end)->shndx() == shndx)
1599ed0d50c3Schristos ++end;
1600ed0d50c3Schristos return Result_pair(start, end);
1601ed0d50c3Schristos }
1602ed0d50c3Schristos
1603ed0d50c3Schristos
1604ed0d50c3Schristos // Add a STUB using KEY. The caller is responsible for avoiding addition
1605ed0d50c3Schristos // if a STUB with the same key has already been added.
1606ed0d50c3Schristos
1607ed0d50c3Schristos template<int size, bool big_endian>
1608ed0d50c3Schristos void
add_reloc_stub(The_reloc_stub * stub,const The_reloc_stub_key & key)1609ed0d50c3Schristos Stub_table<size, big_endian>::add_reloc_stub(
1610ed0d50c3Schristos The_reloc_stub* stub, const The_reloc_stub_key& key)
1611ed0d50c3Schristos {
1612ed0d50c3Schristos gold_assert(stub->type() == key.type());
1613ed0d50c3Schristos this->reloc_stubs_[key] = stub;
1614ed0d50c3Schristos
1615ed0d50c3Schristos // Assign stub offset early. We can do this because we never remove
1616ed0d50c3Schristos // reloc stubs and they are in the beginning of the stub table.
1617ed0d50c3Schristos this->reloc_stubs_size_ = align_address(this->reloc_stubs_size_,
1618ed0d50c3Schristos The_reloc_stub::STUB_ADDR_ALIGN);
1619ed0d50c3Schristos stub->set_offset(this->reloc_stubs_size_);
1620ed0d50c3Schristos this->reloc_stubs_size_ += stub->stub_size();
1621ed0d50c3Schristos }
1622ed0d50c3Schristos
1623ed0d50c3Schristos
162406324dcfSchristos // Relocate an erratum stub.
1625ed0d50c3Schristos
1626ed0d50c3Schristos template<int size, bool big_endian>
1627ed0d50c3Schristos void
1628ed0d50c3Schristos Stub_table<size, big_endian>::
relocate_erratum_stub(The_erratum_stub * estub,unsigned char * view)162906324dcfSchristos relocate_erratum_stub(The_erratum_stub* estub,
163006324dcfSchristos unsigned char* view)
163106324dcfSchristos {
163206324dcfSchristos // Just for convenience.
163306324dcfSchristos const int BPI = AArch64_insn_utilities<big_endian>::BYTES_PER_INSN;
163406324dcfSchristos
163506324dcfSchristos gold_assert(!estub->is_invalidated_erratum_stub());
163606324dcfSchristos AArch64_address stub_address = this->erratum_stub_address(estub);
163706324dcfSchristos // The address of "b" in the stub that is to be "relocated".
163806324dcfSchristos AArch64_address stub_b_insn_address;
163906324dcfSchristos // Branch offset that is to be filled in "b" insn.
164006324dcfSchristos int b_offset = 0;
164106324dcfSchristos switch (estub->type())
164206324dcfSchristos {
164306324dcfSchristos case ST_E_843419:
164406324dcfSchristos case ST_E_835769:
164506324dcfSchristos // The 1st insn of the erratum could be a relocation spot,
164606324dcfSchristos // in this case we need to fix it with
164706324dcfSchristos // "(*i)->erratum_insn()".
164806324dcfSchristos elfcpp::Swap<32, big_endian>::writeval(
164906324dcfSchristos view + (stub_address - this->address()),
165006324dcfSchristos estub->erratum_insn());
165106324dcfSchristos // For the erratum, the 2nd insn is a b-insn to be patched
165206324dcfSchristos // (relocated).
165306324dcfSchristos stub_b_insn_address = stub_address + 1 * BPI;
165406324dcfSchristos b_offset = estub->destination_address() - stub_b_insn_address;
165506324dcfSchristos AArch64_relocate_functions<size, big_endian>::construct_b(
165606324dcfSchristos view + (stub_b_insn_address - this->address()),
165706324dcfSchristos ((unsigned int)(b_offset)) & 0xfffffff);
165806324dcfSchristos break;
165906324dcfSchristos default:
166006324dcfSchristos gold_unreachable();
166106324dcfSchristos break;
166206324dcfSchristos }
166306324dcfSchristos estub->invalidate_erratum_stub();
166406324dcfSchristos }
166506324dcfSchristos
166606324dcfSchristos
166706324dcfSchristos // Relocate only reloc stubs in this stub table. This does not relocate erratum
166806324dcfSchristos // stubs.
166906324dcfSchristos
167006324dcfSchristos template<int size, bool big_endian>
167106324dcfSchristos void
167206324dcfSchristos Stub_table<size, big_endian>::
relocate_reloc_stubs(const The_relocate_info * relinfo,The_target_aarch64 * target_aarch64,Output_section * output_section,unsigned char * view,AArch64_address address,section_size_type view_size)167306324dcfSchristos relocate_reloc_stubs(const The_relocate_info* relinfo,
1674ed0d50c3Schristos The_target_aarch64* target_aarch64,
1675ed0d50c3Schristos Output_section* output_section,
1676ed0d50c3Schristos unsigned char* view,
1677ed0d50c3Schristos AArch64_address address,
1678ed0d50c3Schristos section_size_type view_size)
1679ed0d50c3Schristos {
1680ed0d50c3Schristos // "view_size" is the total size of the stub_table.
1681ed0d50c3Schristos gold_assert(address == this->address() &&
1682ed0d50c3Schristos view_size == static_cast<section_size_type>(this->data_size()));
1683ed0d50c3Schristos for(Reloc_stub_map_const_iter p = this->reloc_stubs_.begin();
1684ed0d50c3Schristos p != this->reloc_stubs_.end(); ++p)
168506324dcfSchristos relocate_reloc_stub(p->second, relinfo, target_aarch64, output_section,
1686ed0d50c3Schristos view, address, view_size);
1687ed0d50c3Schristos }
1688ed0d50c3Schristos
1689ed0d50c3Schristos
169006324dcfSchristos // Relocate one reloc stub. This is a helper for
169106324dcfSchristos // Stub_table::relocate_reloc_stubs().
1692ed0d50c3Schristos
1693ed0d50c3Schristos template<int size, bool big_endian>
1694ed0d50c3Schristos void
1695ed0d50c3Schristos Stub_table<size, big_endian>::
relocate_reloc_stub(The_reloc_stub * stub,const The_relocate_info * relinfo,The_target_aarch64 * target_aarch64,Output_section * output_section,unsigned char * view,AArch64_address address,section_size_type view_size)169606324dcfSchristos relocate_reloc_stub(The_reloc_stub* stub,
1697ed0d50c3Schristos const The_relocate_info* relinfo,
1698ed0d50c3Schristos The_target_aarch64* target_aarch64,
1699ed0d50c3Schristos Output_section* output_section,
1700ed0d50c3Schristos unsigned char* view,
1701ed0d50c3Schristos AArch64_address address,
1702ed0d50c3Schristos section_size_type view_size)
1703ed0d50c3Schristos {
1704ed0d50c3Schristos // "offset" is the offset from the beginning of the stub_table.
1705ed0d50c3Schristos section_size_type offset = stub->offset();
1706ed0d50c3Schristos section_size_type stub_size = stub->stub_size();
1707ed0d50c3Schristos // "view_size" is the total size of the stub_table.
1708ed0d50c3Schristos gold_assert(offset + stub_size <= view_size);
1709ed0d50c3Schristos
171006324dcfSchristos target_aarch64->relocate_reloc_stub(stub, relinfo, output_section,
1711ed0d50c3Schristos view + offset, address + offset, view_size);
1712ed0d50c3Schristos }
1713ed0d50c3Schristos
1714ed0d50c3Schristos
1715ed0d50c3Schristos // Write out the stubs to file.
1716ed0d50c3Schristos
1717ed0d50c3Schristos template<int size, bool big_endian>
1718ed0d50c3Schristos void
do_write(Output_file * of)1719ed0d50c3Schristos Stub_table<size, big_endian>::do_write(Output_file* of)
1720ed0d50c3Schristos {
1721ed0d50c3Schristos off_t offset = this->offset();
1722ed0d50c3Schristos const section_size_type oview_size =
1723ed0d50c3Schristos convert_to_section_size_type(this->data_size());
1724ed0d50c3Schristos unsigned char* const oview = of->get_output_view(offset, oview_size);
1725ed0d50c3Schristos
1726ed0d50c3Schristos // Write relocation stubs.
1727ed0d50c3Schristos for (typename Reloc_stub_map::const_iterator p = this->reloc_stubs_.begin();
1728ed0d50c3Schristos p != this->reloc_stubs_.end(); ++p)
1729ed0d50c3Schristos {
1730ed0d50c3Schristos The_reloc_stub* stub = p->second;
1731ed0d50c3Schristos AArch64_address address = this->address() + stub->offset();
1732ed0d50c3Schristos gold_assert(address ==
1733ed0d50c3Schristos align_address(address, The_reloc_stub::STUB_ADDR_ALIGN));
1734ed0d50c3Schristos stub->write(oview + stub->offset(), stub->stub_size());
1735ed0d50c3Schristos }
1736ed0d50c3Schristos
1737ed0d50c3Schristos // Write erratum stubs.
1738ed0d50c3Schristos unsigned int erratum_stub_start_offset =
1739ed0d50c3Schristos align_address(this->reloc_stubs_size_, The_erratum_stub::STUB_ADDR_ALIGN);
1740ed0d50c3Schristos for (typename Erratum_stub_set::iterator p = this->erratum_stubs_.begin();
1741ed0d50c3Schristos p != this->erratum_stubs_.end(); ++p)
1742ed0d50c3Schristos {
1743ed0d50c3Schristos The_erratum_stub* stub(*p);
1744ed0d50c3Schristos stub->write(oview + erratum_stub_start_offset + stub->offset(),
1745ed0d50c3Schristos stub->stub_size());
1746ed0d50c3Schristos }
1747ed0d50c3Schristos
1748ed0d50c3Schristos of->write_output_view(this->offset(), oview_size, oview);
1749ed0d50c3Schristos }
1750ed0d50c3Schristos
1751ed0d50c3Schristos
1752ed0d50c3Schristos // AArch64_relobj class.
1753ed0d50c3Schristos
1754ed0d50c3Schristos template<int size, bool big_endian>
1755ed0d50c3Schristos class AArch64_relobj : public Sized_relobj_file<size, big_endian>
1756ed0d50c3Schristos {
1757ed0d50c3Schristos public:
1758ed0d50c3Schristos typedef AArch64_relobj<size, big_endian> This;
1759ed0d50c3Schristos typedef Target_aarch64<size, big_endian> The_target_aarch64;
1760ed0d50c3Schristos typedef AArch64_input_section<size, big_endian> The_aarch64_input_section;
1761ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
1762ed0d50c3Schristos typedef Stub_table<size, big_endian> The_stub_table;
1763ed0d50c3Schristos typedef Erratum_stub<size, big_endian> The_erratum_stub;
1764ed0d50c3Schristos typedef typename The_stub_table::Erratum_stub_set_iter Erratum_stub_set_iter;
1765ed0d50c3Schristos typedef std::vector<The_stub_table*> Stub_table_list;
1766ed0d50c3Schristos static const AArch64_address invalid_address =
1767ed0d50c3Schristos static_cast<AArch64_address>(-1);
1768ed0d50c3Schristos
AArch64_relobj(const std::string & name,Input_file * input_file,off_t offset,const typename elfcpp::Ehdr<size,big_endian> & ehdr)1769ed0d50c3Schristos AArch64_relobj(const std::string& name, Input_file* input_file, off_t offset,
1770ed0d50c3Schristos const typename elfcpp::Ehdr<size, big_endian>& ehdr)
1771ed0d50c3Schristos : Sized_relobj_file<size, big_endian>(name, input_file, offset, ehdr),
1772ed0d50c3Schristos stub_tables_()
1773ed0d50c3Schristos { }
1774ed0d50c3Schristos
~AArch64_relobj()1775ed0d50c3Schristos ~AArch64_relobj()
1776ed0d50c3Schristos { }
1777ed0d50c3Schristos
1778ed0d50c3Schristos // Return the stub table of the SHNDX-th section if there is one.
1779ed0d50c3Schristos The_stub_table*
stub_table(unsigned int shndx) const1780ed0d50c3Schristos stub_table(unsigned int shndx) const
1781ed0d50c3Schristos {
1782ed0d50c3Schristos gold_assert(shndx < this->stub_tables_.size());
1783ed0d50c3Schristos return this->stub_tables_[shndx];
1784ed0d50c3Schristos }
1785ed0d50c3Schristos
1786ed0d50c3Schristos // Set STUB_TABLE to be the stub_table of the SHNDX-th section.
1787ed0d50c3Schristos void
set_stub_table(unsigned int shndx,The_stub_table * stub_table)1788ed0d50c3Schristos set_stub_table(unsigned int shndx, The_stub_table* stub_table)
1789ed0d50c3Schristos {
1790ed0d50c3Schristos gold_assert(shndx < this->stub_tables_.size());
1791ed0d50c3Schristos this->stub_tables_[shndx] = stub_table;
1792ed0d50c3Schristos }
1793ed0d50c3Schristos
1794ed0d50c3Schristos // Entrance to errata scanning.
1795ed0d50c3Schristos void
1796ed0d50c3Schristos scan_errata(unsigned int shndx,
1797ed0d50c3Schristos const elfcpp::Shdr<size, big_endian>&,
1798ed0d50c3Schristos Output_section*, const Symbol_table*,
1799ed0d50c3Schristos The_target_aarch64*);
1800ed0d50c3Schristos
1801ed0d50c3Schristos // Scan all relocation sections for stub generation.
1802ed0d50c3Schristos void
1803ed0d50c3Schristos scan_sections_for_stubs(The_target_aarch64*, const Symbol_table*,
1804ed0d50c3Schristos const Layout*);
1805ed0d50c3Schristos
1806ed0d50c3Schristos // Whether a section is a scannable text section.
1807ed0d50c3Schristos bool
1808ed0d50c3Schristos text_section_is_scannable(const elfcpp::Shdr<size, big_endian>&, unsigned int,
1809ed0d50c3Schristos const Output_section*, const Symbol_table*);
1810ed0d50c3Schristos
1811ed0d50c3Schristos // Convert regular input section with index SHNDX to a relaxed section.
1812ed0d50c3Schristos void
convert_input_section_to_relaxed_section(unsigned shndx)181306324dcfSchristos convert_input_section_to_relaxed_section(unsigned shndx)
1814ed0d50c3Schristos {
1815ed0d50c3Schristos // The stubs have relocations and we need to process them after writing
1816ed0d50c3Schristos // out the stubs. So relocation now must follow section write.
181706324dcfSchristos this->set_section_offset(shndx, -1ULL);
1818ed0d50c3Schristos this->set_relocs_must_follow_section_writes();
1819ed0d50c3Schristos }
1820ed0d50c3Schristos
1821ed0d50c3Schristos // Structure for mapping symbol position.
1822ed0d50c3Schristos struct Mapping_symbol_position
1823ed0d50c3Schristos {
Mapping_symbol_position__anond8ca3b600111::AArch64_relobj::Mapping_symbol_position1824ed0d50c3Schristos Mapping_symbol_position(unsigned int shndx, AArch64_address offset):
1825ed0d50c3Schristos shndx_(shndx), offset_(offset)
1826ed0d50c3Schristos {}
1827ed0d50c3Schristos
1828ed0d50c3Schristos // "<" comparator used in ordered_map container.
1829ed0d50c3Schristos bool
operator <__anond8ca3b600111::AArch64_relobj::Mapping_symbol_position1830ed0d50c3Schristos operator<(const Mapping_symbol_position& p) const
1831ed0d50c3Schristos {
1832ed0d50c3Schristos return (this->shndx_ < p.shndx_
1833ed0d50c3Schristos || (this->shndx_ == p.shndx_ && this->offset_ < p.offset_));
1834ed0d50c3Schristos }
1835ed0d50c3Schristos
1836ed0d50c3Schristos // Section index.
1837ed0d50c3Schristos unsigned int shndx_;
1838ed0d50c3Schristos
1839ed0d50c3Schristos // Section offset.
1840ed0d50c3Schristos AArch64_address offset_;
1841ed0d50c3Schristos };
1842ed0d50c3Schristos
1843ed0d50c3Schristos typedef std::map<Mapping_symbol_position, char> Mapping_symbol_info;
1844ed0d50c3Schristos
1845ed0d50c3Schristos protected:
1846ed0d50c3Schristos // Post constructor setup.
1847ed0d50c3Schristos void
do_setup()1848ed0d50c3Schristos do_setup()
1849ed0d50c3Schristos {
1850ed0d50c3Schristos // Call parent's setup method.
1851ed0d50c3Schristos Sized_relobj_file<size, big_endian>::do_setup();
1852ed0d50c3Schristos
1853ed0d50c3Schristos // Initialize look-up tables.
1854ed0d50c3Schristos this->stub_tables_.resize(this->shnum());
1855ed0d50c3Schristos }
1856ed0d50c3Schristos
1857ed0d50c3Schristos virtual void
1858ed0d50c3Schristos do_relocate_sections(
1859ed0d50c3Schristos const Symbol_table* symtab, const Layout* layout,
1860ed0d50c3Schristos const unsigned char* pshdrs, Output_file* of,
1861ed0d50c3Schristos typename Sized_relobj_file<size, big_endian>::Views* pviews);
1862ed0d50c3Schristos
1863ed0d50c3Schristos // Count local symbols and (optionally) record mapping info.
1864ed0d50c3Schristos virtual void
1865ed0d50c3Schristos do_count_local_symbols(Stringpool_template<char>*,
1866ed0d50c3Schristos Stringpool_template<char>*);
1867ed0d50c3Schristos
1868ed0d50c3Schristos private:
186906324dcfSchristos // Fix all errata in the object, and for each erratum, relocate corresponding
187006324dcfSchristos // erratum stub.
1871ed0d50c3Schristos void
187206324dcfSchristos fix_errata_and_relocate_erratum_stubs(
187306324dcfSchristos typename Sized_relobj_file<size, big_endian>::Views* pviews);
1874ed0d50c3Schristos
1875ed0d50c3Schristos // Try to fix erratum 843419 in an optimized way. Return true if patch is
1876ed0d50c3Schristos // applied.
1877ed0d50c3Schristos bool
1878ed0d50c3Schristos try_fix_erratum_843419_optimized(
187906324dcfSchristos The_erratum_stub*, AArch64_address,
1880ed0d50c3Schristos typename Sized_relobj_file<size, big_endian>::View_size&);
1881ed0d50c3Schristos
1882ed0d50c3Schristos // Whether a section needs to be scanned for relocation stubs.
1883ed0d50c3Schristos bool
1884ed0d50c3Schristos section_needs_reloc_stub_scanning(const elfcpp::Shdr<size, big_endian>&,
1885ed0d50c3Schristos const Relobj::Output_sections&,
1886ed0d50c3Schristos const Symbol_table*, const unsigned char*);
1887ed0d50c3Schristos
1888ed0d50c3Schristos // List of stub tables.
1889ed0d50c3Schristos Stub_table_list stub_tables_;
1890ed0d50c3Schristos
1891ed0d50c3Schristos // Mapping symbol information sorted by (section index, section_offset).
1892ed0d50c3Schristos Mapping_symbol_info mapping_symbol_info_;
1893ed0d50c3Schristos }; // End of AArch64_relobj
1894ed0d50c3Schristos
1895ed0d50c3Schristos
1896ed0d50c3Schristos // Override to record mapping symbol information.
1897ed0d50c3Schristos template<int size, bool big_endian>
1898ed0d50c3Schristos void
do_count_local_symbols(Stringpool_template<char> * pool,Stringpool_template<char> * dynpool)1899ed0d50c3Schristos AArch64_relobj<size, big_endian>::do_count_local_symbols(
1900ed0d50c3Schristos Stringpool_template<char>* pool, Stringpool_template<char>* dynpool)
1901ed0d50c3Schristos {
1902ed0d50c3Schristos Sized_relobj_file<size, big_endian>::do_count_local_symbols(pool, dynpool);
1903ed0d50c3Schristos
1904ed0d50c3Schristos // Only erratum-fixing work needs mapping symbols, so skip this time consuming
1905ed0d50c3Schristos // processing if not fixing erratum.
1906ed0d50c3Schristos if (!parameters->options().fix_cortex_a53_843419()
1907ed0d50c3Schristos && !parameters->options().fix_cortex_a53_835769())
1908ed0d50c3Schristos return;
1909ed0d50c3Schristos
1910ed0d50c3Schristos const unsigned int loccount = this->local_symbol_count();
1911ed0d50c3Schristos if (loccount == 0)
1912ed0d50c3Schristos return;
1913ed0d50c3Schristos
1914ed0d50c3Schristos // Read the symbol table section header.
1915ed0d50c3Schristos const unsigned int symtab_shndx = this->symtab_shndx();
1916ed0d50c3Schristos elfcpp::Shdr<size, big_endian>
1917ed0d50c3Schristos symtabshdr(this, this->elf_file()->section_header(symtab_shndx));
1918ed0d50c3Schristos gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
1919ed0d50c3Schristos
1920ed0d50c3Schristos // Read the local symbols.
1921ed0d50c3Schristos const int sym_size =elfcpp::Elf_sizes<size>::sym_size;
1922ed0d50c3Schristos gold_assert(loccount == symtabshdr.get_sh_info());
1923ed0d50c3Schristos off_t locsize = loccount * sym_size;
1924ed0d50c3Schristos const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
1925ed0d50c3Schristos locsize, true, true);
1926ed0d50c3Schristos
1927ed0d50c3Schristos // For mapping symbol processing, we need to read the symbol names.
1928ed0d50c3Schristos unsigned int strtab_shndx = this->adjust_shndx(symtabshdr.get_sh_link());
1929ed0d50c3Schristos if (strtab_shndx >= this->shnum())
1930ed0d50c3Schristos {
1931ed0d50c3Schristos this->error(_("invalid symbol table name index: %u"), strtab_shndx);
1932ed0d50c3Schristos return;
1933ed0d50c3Schristos }
1934ed0d50c3Schristos
1935ed0d50c3Schristos elfcpp::Shdr<size, big_endian>
1936ed0d50c3Schristos strtabshdr(this, this->elf_file()->section_header(strtab_shndx));
1937ed0d50c3Schristos if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB)
1938ed0d50c3Schristos {
1939ed0d50c3Schristos this->error(_("symbol table name section has wrong type: %u"),
1940ed0d50c3Schristos static_cast<unsigned int>(strtabshdr.get_sh_type()));
1941ed0d50c3Schristos return;
1942ed0d50c3Schristos }
1943ed0d50c3Schristos
1944ed0d50c3Schristos const char* pnames =
1945ed0d50c3Schristos reinterpret_cast<const char*>(this->get_view(strtabshdr.get_sh_offset(),
1946ed0d50c3Schristos strtabshdr.get_sh_size(),
1947ed0d50c3Schristos false, false));
1948ed0d50c3Schristos
1949ed0d50c3Schristos // Skip the first dummy symbol.
1950ed0d50c3Schristos psyms += sym_size;
1951ed0d50c3Schristos typename Sized_relobj_file<size, big_endian>::Local_values*
1952ed0d50c3Schristos plocal_values = this->local_values();
1953ed0d50c3Schristos for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
1954ed0d50c3Schristos {
1955ed0d50c3Schristos elfcpp::Sym<size, big_endian> sym(psyms);
1956ed0d50c3Schristos Symbol_value<size>& lv((*plocal_values)[i]);
1957ed0d50c3Schristos AArch64_address input_value = lv.input_value();
1958ed0d50c3Schristos
1959ed0d50c3Schristos // Check to see if this is a mapping symbol. AArch64 mapping symbols are
1960ed0d50c3Schristos // defined in "ELF for the ARM 64-bit Architecture", Table 4-4, Mapping
1961ed0d50c3Schristos // symbols.
1962ed0d50c3Schristos // Mapping symbols could be one of the following 4 forms -
1963ed0d50c3Schristos // a) $x
1964ed0d50c3Schristos // b) $x.<any...>
1965ed0d50c3Schristos // c) $d
1966ed0d50c3Schristos // d) $d.<any...>
1967ed0d50c3Schristos const char* sym_name = pnames + sym.get_st_name();
1968ed0d50c3Schristos if (sym_name[0] == '$' && (sym_name[1] == 'x' || sym_name[1] == 'd')
1969ed0d50c3Schristos && (sym_name[2] == '\0' || sym_name[2] == '.'))
1970ed0d50c3Schristos {
1971ed0d50c3Schristos bool is_ordinary;
1972ed0d50c3Schristos unsigned int input_shndx =
1973ed0d50c3Schristos this->adjust_sym_shndx(i, sym.get_st_shndx(), &is_ordinary);
1974ed0d50c3Schristos gold_assert(is_ordinary);
1975ed0d50c3Schristos
1976ed0d50c3Schristos Mapping_symbol_position msp(input_shndx, input_value);
1977ed0d50c3Schristos // Insert mapping_symbol_info into map whose ordering is defined by
1978ed0d50c3Schristos // (shndx, offset_within_section).
1979ed0d50c3Schristos this->mapping_symbol_info_[msp] = sym_name[1];
1980ed0d50c3Schristos }
1981ed0d50c3Schristos }
1982ed0d50c3Schristos }
1983ed0d50c3Schristos
1984ed0d50c3Schristos
198506324dcfSchristos // Fix all errata in the object and for each erratum, we relocate the
198606324dcfSchristos // corresponding erratum stub (by calling Stub_table::relocate_erratum_stub).
1987ed0d50c3Schristos
1988ed0d50c3Schristos template<int size, bool big_endian>
1989ed0d50c3Schristos void
fix_errata_and_relocate_erratum_stubs(typename Sized_relobj_file<size,big_endian>::Views * pviews)199006324dcfSchristos AArch64_relobj<size, big_endian>::fix_errata_and_relocate_erratum_stubs(
1991ed0d50c3Schristos typename Sized_relobj_file<size, big_endian>::Views* pviews)
1992ed0d50c3Schristos {
1993ed0d50c3Schristos typedef typename elfcpp::Swap<32,big_endian>::Valtype Insntype;
1994ed0d50c3Schristos unsigned int shnum = this->shnum();
199506324dcfSchristos const Relobj::Output_sections& out_sections(this->output_sections());
1996ed0d50c3Schristos for (unsigned int i = 1; i < shnum; ++i)
1997ed0d50c3Schristos {
1998ed0d50c3Schristos The_stub_table* stub_table = this->stub_table(i);
1999ed0d50c3Schristos if (!stub_table)
2000ed0d50c3Schristos continue;
2001ed0d50c3Schristos std::pair<Erratum_stub_set_iter, Erratum_stub_set_iter>
2002ed0d50c3Schristos ipair(stub_table->find_erratum_stubs_for_input_section(this, i));
2003ed0d50c3Schristos Erratum_stub_set_iter p = ipair.first, end = ipair.second;
200406324dcfSchristos typename Sized_relobj_file<size, big_endian>::View_size&
200506324dcfSchristos pview((*pviews)[i]);
200606324dcfSchristos AArch64_address view_offset = 0;
200706324dcfSchristos if (pview.is_input_output_view)
200806324dcfSchristos {
200906324dcfSchristos // In this case, write_sections has not added the output offset to
201006324dcfSchristos // the view's address, so we must do so. Currently this only happens
201106324dcfSchristos // for a relaxed section.
201206324dcfSchristos unsigned int index = this->adjust_shndx(i);
201306324dcfSchristos const Output_relaxed_input_section* poris =
201406324dcfSchristos out_sections[index]->find_relaxed_input_section(this, index);
201506324dcfSchristos gold_assert(poris != NULL);
201606324dcfSchristos view_offset = poris->address() - pview.address;
201706324dcfSchristos }
201806324dcfSchristos
2019ed0d50c3Schristos while (p != end)
2020ed0d50c3Schristos {
2021ed0d50c3Schristos The_erratum_stub* stub = *p;
2022ed0d50c3Schristos
2023ed0d50c3Schristos // Double check data before fix.
202406324dcfSchristos gold_assert(pview.address + view_offset + stub->sh_offset()
2025ed0d50c3Schristos == stub->erratum_address());
2026ed0d50c3Schristos
2027ed0d50c3Schristos // Update previously recorded erratum insn with relocated
2028ed0d50c3Schristos // version.
2029ed0d50c3Schristos Insntype* ip =
203006324dcfSchristos reinterpret_cast<Insntype*>(
203106324dcfSchristos pview.view + view_offset + stub->sh_offset());
2032ed0d50c3Schristos Insntype insn_to_fix = ip[0];
2033ed0d50c3Schristos stub->update_erratum_insn(insn_to_fix);
2034ed0d50c3Schristos
2035ed0d50c3Schristos // First try to see if erratum is 843419 and if it can be fixed
2036ed0d50c3Schristos // without using branch-to-stub.
203706324dcfSchristos if (!try_fix_erratum_843419_optimized(stub, view_offset, pview))
2038ed0d50c3Schristos {
2039ed0d50c3Schristos // Replace the erratum insn with a branch-to-stub.
2040ed0d50c3Schristos AArch64_address stub_address =
2041ed0d50c3Schristos stub_table->erratum_stub_address(stub);
2042ed0d50c3Schristos unsigned int b_offset = stub_address - stub->erratum_address();
2043ed0d50c3Schristos AArch64_relocate_functions<size, big_endian>::construct_b(
204406324dcfSchristos pview.view + view_offset + stub->sh_offset(),
204506324dcfSchristos b_offset & 0xfffffff);
2046ed0d50c3Schristos }
204706324dcfSchristos
204806324dcfSchristos // Erratum fix is done (or skipped), continue to relocate erratum
204906324dcfSchristos // stub. Note, when erratum fix is skipped (either because we
205006324dcfSchristos // proactively change the code sequence or the code sequence is
205106324dcfSchristos // changed by relaxation, etc), we can still safely relocate the
205206324dcfSchristos // erratum stub, ignoring the fact the erratum could never be
205306324dcfSchristos // executed.
205406324dcfSchristos stub_table->relocate_erratum_stub(
205506324dcfSchristos stub,
205606324dcfSchristos pview.view + (stub_table->address() - pview.address));
205706324dcfSchristos
205806324dcfSchristos // Next erratum stub.
2059ed0d50c3Schristos ++p;
2060ed0d50c3Schristos }
2061ed0d50c3Schristos }
2062ed0d50c3Schristos }
2063ed0d50c3Schristos
2064ed0d50c3Schristos
2065ed0d50c3Schristos // This is an optimization for 843419. This erratum requires the sequence begin
2066ed0d50c3Schristos // with 'adrp', when final value calculated by adrp fits in adr, we can just
2067ed0d50c3Schristos // replace 'adrp' with 'adr', so we save 2 jumps per occurrence. (Note, however,
2068ed0d50c3Schristos // in this case, we do not delete the erratum stub (too late to do so), it is
2069ed0d50c3Schristos // merely generated without ever being called.)
2070ed0d50c3Schristos
2071ed0d50c3Schristos template<int size, bool big_endian>
2072ed0d50c3Schristos bool
try_fix_erratum_843419_optimized(The_erratum_stub * stub,AArch64_address view_offset,typename Sized_relobj_file<size,big_endian>::View_size & pview)2073ed0d50c3Schristos AArch64_relobj<size, big_endian>::try_fix_erratum_843419_optimized(
207406324dcfSchristos The_erratum_stub* stub, AArch64_address view_offset,
2075ed0d50c3Schristos typename Sized_relobj_file<size, big_endian>::View_size& pview)
2076ed0d50c3Schristos {
2077ed0d50c3Schristos if (stub->type() != ST_E_843419)
2078ed0d50c3Schristos return false;
2079ed0d50c3Schristos
2080ed0d50c3Schristos typedef AArch64_insn_utilities<big_endian> Insn_utilities;
2081ed0d50c3Schristos typedef typename elfcpp::Swap<32,big_endian>::Valtype Insntype;
2082ed0d50c3Schristos E843419_stub<size, big_endian>* e843419_stub =
2083ed0d50c3Schristos reinterpret_cast<E843419_stub<size, big_endian>*>(stub);
208406324dcfSchristos AArch64_address pc =
208506324dcfSchristos pview.address + view_offset + e843419_stub->adrp_sh_offset();
208606324dcfSchristos unsigned int adrp_offset = e843419_stub->adrp_sh_offset ();
208706324dcfSchristos Insntype* adrp_view =
208806324dcfSchristos reinterpret_cast<Insntype*>(pview.view + view_offset + adrp_offset);
2089ed0d50c3Schristos Insntype adrp_insn = adrp_view[0];
209006324dcfSchristos
209106324dcfSchristos // If the instruction at adrp_sh_offset is "mrs R, tpidr_el0", it may come
209206324dcfSchristos // from IE -> LE relaxation etc. This is a side-effect of TLS relaxation that
209306324dcfSchristos // ADRP has been turned into MRS, there is no erratum risk anymore.
209406324dcfSchristos // Therefore, we return true to avoid doing unnecessary branch-to-stub.
209506324dcfSchristos if (Insn_utilities::is_mrs_tpidr_el0(adrp_insn))
209606324dcfSchristos return true;
209706324dcfSchristos
209806324dcfSchristos // If the instruction at adrp_sh_offset is not ADRP and the instruction before
209906324dcfSchristos // it is "mrs R, tpidr_el0", it may come from LD -> LE relaxation etc.
210006324dcfSchristos // Like the above case, there is no erratum risk any more, we can safely
210106324dcfSchristos // return true.
210206324dcfSchristos if (!Insn_utilities::is_adrp(adrp_insn) && adrp_offset)
210306324dcfSchristos {
210406324dcfSchristos Insntype* prev_view =
210506324dcfSchristos reinterpret_cast<Insntype*>(
210606324dcfSchristos pview.view + view_offset + adrp_offset - 4);
210706324dcfSchristos Insntype prev_insn = prev_view[0];
210806324dcfSchristos
210906324dcfSchristos if (Insn_utilities::is_mrs_tpidr_el0(prev_insn))
211006324dcfSchristos return true;
211106324dcfSchristos }
211206324dcfSchristos
211306324dcfSchristos /* If we reach here, the first instruction must be ADRP. */
2114ed0d50c3Schristos gold_assert(Insn_utilities::is_adrp(adrp_insn));
2115ed0d50c3Schristos // Get adrp 33-bit signed imm value.
2116ed0d50c3Schristos int64_t adrp_imm = Insn_utilities::
2117ed0d50c3Schristos aarch64_adrp_decode_imm(adrp_insn);
2118ed0d50c3Schristos // adrp - final value transferred to target register is calculated as:
2119ed0d50c3Schristos // PC[11:0] = Zeros(12)
2120ed0d50c3Schristos // adrp_dest_value = PC + adrp_imm;
2121ed0d50c3Schristos int64_t adrp_dest_value = (pc & ~((1 << 12) - 1)) + adrp_imm;
2122ed0d50c3Schristos // adr -final value transferred to target register is calucalted as:
2123ed0d50c3Schristos // PC + adr_imm
2124ed0d50c3Schristos // So we have:
2125ed0d50c3Schristos // PC + adr_imm = adrp_dest_value
2126ed0d50c3Schristos // ==>
2127ed0d50c3Schristos // adr_imm = adrp_dest_value - PC
2128ed0d50c3Schristos int64_t adr_imm = adrp_dest_value - pc;
2129ed0d50c3Schristos // Check if imm fits in adr (21-bit signed).
2130ed0d50c3Schristos if (-(1 << 20) <= adr_imm && adr_imm < (1 << 20))
2131ed0d50c3Schristos {
2132ed0d50c3Schristos // Convert 'adrp' into 'adr'.
2133ed0d50c3Schristos Insntype adr_insn = adrp_insn & ((1u << 31) - 1);
2134ed0d50c3Schristos adr_insn = Insn_utilities::
2135ed0d50c3Schristos aarch64_adr_encode_imm(adr_insn, adr_imm);
2136ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(adrp_view, adr_insn);
2137ed0d50c3Schristos return true;
2138ed0d50c3Schristos }
2139ed0d50c3Schristos return false;
2140ed0d50c3Schristos }
2141ed0d50c3Schristos
2142ed0d50c3Schristos
2143ed0d50c3Schristos // Relocate sections.
2144ed0d50c3Schristos
2145ed0d50c3Schristos template<int size, bool big_endian>
2146ed0d50c3Schristos void
do_relocate_sections(const Symbol_table * symtab,const Layout * layout,const unsigned char * pshdrs,Output_file * of,typename Sized_relobj_file<size,big_endian>::Views * pviews)2147ed0d50c3Schristos AArch64_relobj<size, big_endian>::do_relocate_sections(
2148ed0d50c3Schristos const Symbol_table* symtab, const Layout* layout,
2149ed0d50c3Schristos const unsigned char* pshdrs, Output_file* of,
2150ed0d50c3Schristos typename Sized_relobj_file<size, big_endian>::Views* pviews)
2151ed0d50c3Schristos {
215206324dcfSchristos // Relocate the section data.
215306324dcfSchristos this->relocate_section_range(symtab, layout, pshdrs, of, pviews,
215406324dcfSchristos 1, this->shnum() - 1);
2155ed0d50c3Schristos
2156ed0d50c3Schristos // We do not generate stubs if doing a relocatable link.
2157ed0d50c3Schristos if (parameters->options().relocatable())
2158ed0d50c3Schristos return;
2159ed0d50c3Schristos
216006324dcfSchristos // This part only relocates erratum stubs that belong to input sections of this
216106324dcfSchristos // object file.
2162ed0d50c3Schristos if (parameters->options().fix_cortex_a53_843419()
2163ed0d50c3Schristos || parameters->options().fix_cortex_a53_835769())
216406324dcfSchristos this->fix_errata_and_relocate_erratum_stubs(pviews);
2165ed0d50c3Schristos
2166ed0d50c3Schristos Relocate_info<size, big_endian> relinfo;
2167ed0d50c3Schristos relinfo.symtab = symtab;
2168ed0d50c3Schristos relinfo.layout = layout;
2169ed0d50c3Schristos relinfo.object = this;
2170ed0d50c3Schristos
217106324dcfSchristos // This part relocates all reloc stubs that are contained in stub_tables of
217206324dcfSchristos // this object file.
2173ed0d50c3Schristos unsigned int shnum = this->shnum();
2174ed0d50c3Schristos The_target_aarch64* target = The_target_aarch64::current_target();
2175ed0d50c3Schristos
2176ed0d50c3Schristos for (unsigned int i = 1; i < shnum; ++i)
2177ed0d50c3Schristos {
2178ed0d50c3Schristos The_aarch64_input_section* aarch64_input_section =
2179ed0d50c3Schristos target->find_aarch64_input_section(this, i);
2180ed0d50c3Schristos if (aarch64_input_section != NULL
2181ed0d50c3Schristos && aarch64_input_section->is_stub_table_owner()
2182ed0d50c3Schristos && !aarch64_input_section->stub_table()->empty())
2183ed0d50c3Schristos {
2184ed0d50c3Schristos Output_section* os = this->output_section(i);
2185ed0d50c3Schristos gold_assert(os != NULL);
2186ed0d50c3Schristos
2187ed0d50c3Schristos relinfo.reloc_shndx = elfcpp::SHN_UNDEF;
2188ed0d50c3Schristos relinfo.reloc_shdr = NULL;
2189ed0d50c3Schristos relinfo.data_shndx = i;
2190ed0d50c3Schristos relinfo.data_shdr = pshdrs + i * elfcpp::Elf_sizes<size>::shdr_size;
2191ed0d50c3Schristos
2192ed0d50c3Schristos typename Sized_relobj_file<size, big_endian>::View_size&
2193ed0d50c3Schristos view_struct = (*pviews)[i];
2194ed0d50c3Schristos gold_assert(view_struct.view != NULL);
2195ed0d50c3Schristos
2196ed0d50c3Schristos The_stub_table* stub_table = aarch64_input_section->stub_table();
2197ed0d50c3Schristos off_t offset = stub_table->address() - view_struct.address;
2198ed0d50c3Schristos unsigned char* view = view_struct.view + offset;
2199ed0d50c3Schristos AArch64_address address = stub_table->address();
2200ed0d50c3Schristos section_size_type view_size = stub_table->data_size();
220106324dcfSchristos stub_table->relocate_reloc_stubs(&relinfo, target, os, view, address,
2202ed0d50c3Schristos view_size);
2203ed0d50c3Schristos }
2204ed0d50c3Schristos }
2205ed0d50c3Schristos }
2206ed0d50c3Schristos
2207ed0d50c3Schristos
2208ed0d50c3Schristos // Determine if an input section is scannable for stub processing. SHDR is
2209ed0d50c3Schristos // the header of the section and SHNDX is the section index. OS is the output
2210ed0d50c3Schristos // section for the input section and SYMTAB is the global symbol table used to
2211ed0d50c3Schristos // look up ICF information.
2212ed0d50c3Schristos
2213ed0d50c3Schristos template<int size, bool big_endian>
2214ed0d50c3Schristos bool
text_section_is_scannable(const elfcpp::Shdr<size,big_endian> & text_shdr,unsigned int text_shndx,const Output_section * os,const Symbol_table * symtab)2215ed0d50c3Schristos AArch64_relobj<size, big_endian>::text_section_is_scannable(
2216ed0d50c3Schristos const elfcpp::Shdr<size, big_endian>& text_shdr,
2217ed0d50c3Schristos unsigned int text_shndx,
2218ed0d50c3Schristos const Output_section* os,
2219ed0d50c3Schristos const Symbol_table* symtab)
2220ed0d50c3Schristos {
2221ed0d50c3Schristos // Skip any empty sections, unallocated sections or sections whose
2222ed0d50c3Schristos // type are not SHT_PROGBITS.
2223ed0d50c3Schristos if (text_shdr.get_sh_size() == 0
2224ed0d50c3Schristos || (text_shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0
2225ed0d50c3Schristos || text_shdr.get_sh_type() != elfcpp::SHT_PROGBITS)
2226ed0d50c3Schristos return false;
2227ed0d50c3Schristos
2228ed0d50c3Schristos // Skip any discarded or ICF'ed sections.
2229ed0d50c3Schristos if (os == NULL || symtab->is_section_folded(this, text_shndx))
2230ed0d50c3Schristos return false;
2231ed0d50c3Schristos
2232ed0d50c3Schristos // Skip exception frame.
2233ed0d50c3Schristos if (strcmp(os->name(), ".eh_frame") == 0)
2234ed0d50c3Schristos return false ;
2235ed0d50c3Schristos
2236ed0d50c3Schristos gold_assert(!this->is_output_section_offset_invalid(text_shndx) ||
2237ed0d50c3Schristos os->find_relaxed_input_section(this, text_shndx) != NULL);
2238ed0d50c3Schristos
2239ed0d50c3Schristos return true;
2240ed0d50c3Schristos }
2241ed0d50c3Schristos
2242ed0d50c3Schristos
2243ed0d50c3Schristos // Determine if we want to scan the SHNDX-th section for relocation stubs.
2244ed0d50c3Schristos // This is a helper for AArch64_relobj::scan_sections_for_stubs().
2245ed0d50c3Schristos
2246ed0d50c3Schristos template<int size, bool big_endian>
2247ed0d50c3Schristos bool
section_needs_reloc_stub_scanning(const elfcpp::Shdr<size,big_endian> & shdr,const Relobj::Output_sections & out_sections,const Symbol_table * symtab,const unsigned char * pshdrs)2248ed0d50c3Schristos AArch64_relobj<size, big_endian>::section_needs_reloc_stub_scanning(
2249ed0d50c3Schristos const elfcpp::Shdr<size, big_endian>& shdr,
2250ed0d50c3Schristos const Relobj::Output_sections& out_sections,
2251ed0d50c3Schristos const Symbol_table* symtab,
2252ed0d50c3Schristos const unsigned char* pshdrs)
2253ed0d50c3Schristos {
2254ed0d50c3Schristos unsigned int sh_type = shdr.get_sh_type();
2255ed0d50c3Schristos if (sh_type != elfcpp::SHT_RELA)
2256ed0d50c3Schristos return false;
2257ed0d50c3Schristos
2258ed0d50c3Schristos // Ignore empty section.
2259ed0d50c3Schristos off_t sh_size = shdr.get_sh_size();
2260ed0d50c3Schristos if (sh_size == 0)
2261ed0d50c3Schristos return false;
2262ed0d50c3Schristos
2263ed0d50c3Schristos // Ignore reloc section with unexpected symbol table. The
2264ed0d50c3Schristos // error will be reported in the final link.
2265ed0d50c3Schristos if (this->adjust_shndx(shdr.get_sh_link()) != this->symtab_shndx())
2266ed0d50c3Schristos return false;
2267ed0d50c3Schristos
2268ed0d50c3Schristos gold_assert(sh_type == elfcpp::SHT_RELA);
2269ed0d50c3Schristos unsigned int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
2270ed0d50c3Schristos
2271ed0d50c3Schristos // Ignore reloc section with unexpected entsize or uneven size.
2272ed0d50c3Schristos // The error will be reported in the final link.
2273ed0d50c3Schristos if (reloc_size != shdr.get_sh_entsize() || sh_size % reloc_size != 0)
2274ed0d50c3Schristos return false;
2275ed0d50c3Schristos
2276ed0d50c3Schristos // Ignore reloc section with bad info. This error will be
2277ed0d50c3Schristos // reported in the final link.
2278ed0d50c3Schristos unsigned int text_shndx = this->adjust_shndx(shdr.get_sh_info());
2279ed0d50c3Schristos if (text_shndx >= this->shnum())
2280ed0d50c3Schristos return false;
2281ed0d50c3Schristos
2282ed0d50c3Schristos const unsigned int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
2283ed0d50c3Schristos const elfcpp::Shdr<size, big_endian> text_shdr(pshdrs +
2284ed0d50c3Schristos text_shndx * shdr_size);
2285ed0d50c3Schristos return this->text_section_is_scannable(text_shdr, text_shndx,
2286ed0d50c3Schristos out_sections[text_shndx], symtab);
2287ed0d50c3Schristos }
2288ed0d50c3Schristos
2289ed0d50c3Schristos
2290ed0d50c3Schristos // Scan section SHNDX for erratum 843419 and 835769.
2291ed0d50c3Schristos
2292ed0d50c3Schristos template<int size, bool big_endian>
2293ed0d50c3Schristos void
scan_errata(unsigned int shndx,const elfcpp::Shdr<size,big_endian> & shdr,Output_section * os,const Symbol_table * symtab,The_target_aarch64 * target)2294ed0d50c3Schristos AArch64_relobj<size, big_endian>::scan_errata(
2295ed0d50c3Schristos unsigned int shndx, const elfcpp::Shdr<size, big_endian>& shdr,
2296ed0d50c3Schristos Output_section* os, const Symbol_table* symtab,
2297ed0d50c3Schristos The_target_aarch64* target)
2298ed0d50c3Schristos {
2299ed0d50c3Schristos if (shdr.get_sh_size() == 0
2300ed0d50c3Schristos || (shdr.get_sh_flags() &
2301ed0d50c3Schristos (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR)) == 0
2302ed0d50c3Schristos || shdr.get_sh_type() != elfcpp::SHT_PROGBITS)
2303ed0d50c3Schristos return;
2304ed0d50c3Schristos
2305ed0d50c3Schristos if (!os || symtab->is_section_folded(this, shndx)) return;
2306ed0d50c3Schristos
2307ed0d50c3Schristos AArch64_address output_offset = this->get_output_section_offset(shndx);
2308ed0d50c3Schristos AArch64_address output_address;
2309ed0d50c3Schristos if (output_offset != invalid_address)
2310ed0d50c3Schristos output_address = os->address() + output_offset;
2311ed0d50c3Schristos else
2312ed0d50c3Schristos {
2313ed0d50c3Schristos const Output_relaxed_input_section* poris =
2314ed0d50c3Schristos os->find_relaxed_input_section(this, shndx);
2315ed0d50c3Schristos if (!poris) return;
2316ed0d50c3Schristos output_address = poris->address();
2317ed0d50c3Schristos }
2318ed0d50c3Schristos
231906324dcfSchristos // Update the addresses in previously generated erratum stubs. Unlike when
232006324dcfSchristos // we scan relocations for stubs, if section addresses have changed due to
232106324dcfSchristos // other relaxations we are unlikely to scan the same erratum instances
232206324dcfSchristos // again.
232306324dcfSchristos The_stub_table* stub_table = this->stub_table(shndx);
232406324dcfSchristos if (stub_table)
232506324dcfSchristos {
232606324dcfSchristos std::pair<Erratum_stub_set_iter, Erratum_stub_set_iter>
232706324dcfSchristos ipair(stub_table->find_erratum_stubs_for_input_section(this, shndx));
232806324dcfSchristos for (Erratum_stub_set_iter p = ipair.first; p != ipair.second; ++p)
232906324dcfSchristos (*p)->update_erratum_address(output_address);
233006324dcfSchristos }
233106324dcfSchristos
2332ed0d50c3Schristos section_size_type input_view_size = 0;
2333ed0d50c3Schristos const unsigned char* input_view =
2334ed0d50c3Schristos this->section_contents(shndx, &input_view_size, false);
2335ed0d50c3Schristos
2336ed0d50c3Schristos Mapping_symbol_position section_start(shndx, 0);
2337ed0d50c3Schristos // Find the first mapping symbol record within section shndx.
2338ed0d50c3Schristos typename Mapping_symbol_info::const_iterator p =
2339ed0d50c3Schristos this->mapping_symbol_info_.lower_bound(section_start);
2340ed0d50c3Schristos while (p != this->mapping_symbol_info_.end() &&
2341ed0d50c3Schristos p->first.shndx_ == shndx)
2342ed0d50c3Schristos {
2343ed0d50c3Schristos typename Mapping_symbol_info::const_iterator prev = p;
2344ed0d50c3Schristos ++p;
2345ed0d50c3Schristos if (prev->second == 'x')
2346ed0d50c3Schristos {
2347ed0d50c3Schristos section_size_type span_start =
2348ed0d50c3Schristos convert_to_section_size_type(prev->first.offset_);
2349ed0d50c3Schristos section_size_type span_end;
2350ed0d50c3Schristos if (p != this->mapping_symbol_info_.end()
2351ed0d50c3Schristos && p->first.shndx_ == shndx)
2352ed0d50c3Schristos span_end = convert_to_section_size_type(p->first.offset_);
2353ed0d50c3Schristos else
2354ed0d50c3Schristos span_end = convert_to_section_size_type(shdr.get_sh_size());
2355ed0d50c3Schristos
2356ed0d50c3Schristos // Here we do not share the scanning code of both errata. For 843419,
2357ed0d50c3Schristos // only the last few insns of each page are examined, which is fast,
2358ed0d50c3Schristos // whereas, for 835769, every insn pair needs to be checked.
2359ed0d50c3Schristos
2360ed0d50c3Schristos if (parameters->options().fix_cortex_a53_843419())
2361ed0d50c3Schristos target->scan_erratum_843419_span(
2362ed0d50c3Schristos this, shndx, span_start, span_end,
2363ed0d50c3Schristos const_cast<unsigned char*>(input_view), output_address);
2364ed0d50c3Schristos
2365ed0d50c3Schristos if (parameters->options().fix_cortex_a53_835769())
2366ed0d50c3Schristos target->scan_erratum_835769_span(
2367ed0d50c3Schristos this, shndx, span_start, span_end,
2368ed0d50c3Schristos const_cast<unsigned char*>(input_view), output_address);
2369ed0d50c3Schristos }
2370ed0d50c3Schristos }
2371ed0d50c3Schristos }
2372ed0d50c3Schristos
2373ed0d50c3Schristos
2374ed0d50c3Schristos // Scan relocations for stub generation.
2375ed0d50c3Schristos
2376ed0d50c3Schristos template<int size, bool big_endian>
2377ed0d50c3Schristos void
scan_sections_for_stubs(The_target_aarch64 * target,const Symbol_table * symtab,const Layout * layout)2378ed0d50c3Schristos AArch64_relobj<size, big_endian>::scan_sections_for_stubs(
2379ed0d50c3Schristos The_target_aarch64* target,
2380ed0d50c3Schristos const Symbol_table* symtab,
2381ed0d50c3Schristos const Layout* layout)
2382ed0d50c3Schristos {
2383ed0d50c3Schristos unsigned int shnum = this->shnum();
2384ed0d50c3Schristos const unsigned int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
2385ed0d50c3Schristos
2386ed0d50c3Schristos // Read the section headers.
2387ed0d50c3Schristos const unsigned char* pshdrs = this->get_view(this->elf_file()->shoff(),
2388ed0d50c3Schristos shnum * shdr_size,
2389ed0d50c3Schristos true, true);
2390ed0d50c3Schristos
2391ed0d50c3Schristos // To speed up processing, we set up hash tables for fast lookup of
2392ed0d50c3Schristos // input offsets to output addresses.
2393ed0d50c3Schristos this->initialize_input_to_output_maps();
2394ed0d50c3Schristos
2395ed0d50c3Schristos const Relobj::Output_sections& out_sections(this->output_sections());
2396ed0d50c3Schristos
2397ed0d50c3Schristos Relocate_info<size, big_endian> relinfo;
2398ed0d50c3Schristos relinfo.symtab = symtab;
2399ed0d50c3Schristos relinfo.layout = layout;
2400ed0d50c3Schristos relinfo.object = this;
2401ed0d50c3Schristos
2402ed0d50c3Schristos // Do relocation stubs scanning.
2403ed0d50c3Schristos const unsigned char* p = pshdrs + shdr_size;
2404ed0d50c3Schristos for (unsigned int i = 1; i < shnum; ++i, p += shdr_size)
2405ed0d50c3Schristos {
2406ed0d50c3Schristos const elfcpp::Shdr<size, big_endian> shdr(p);
2407ed0d50c3Schristos if (parameters->options().fix_cortex_a53_843419()
2408ed0d50c3Schristos || parameters->options().fix_cortex_a53_835769())
2409ed0d50c3Schristos scan_errata(i, shdr, out_sections[i], symtab, target);
2410ed0d50c3Schristos if (this->section_needs_reloc_stub_scanning(shdr, out_sections, symtab,
2411ed0d50c3Schristos pshdrs))
2412ed0d50c3Schristos {
2413ed0d50c3Schristos unsigned int index = this->adjust_shndx(shdr.get_sh_info());
2414ed0d50c3Schristos AArch64_address output_offset =
2415ed0d50c3Schristos this->get_output_section_offset(index);
2416ed0d50c3Schristos AArch64_address output_address;
2417ed0d50c3Schristos if (output_offset != invalid_address)
2418ed0d50c3Schristos {
2419ed0d50c3Schristos output_address = out_sections[index]->address() + output_offset;
2420ed0d50c3Schristos }
2421ed0d50c3Schristos else
2422ed0d50c3Schristos {
2423ed0d50c3Schristos // Currently this only happens for a relaxed section.
2424ed0d50c3Schristos const Output_relaxed_input_section* poris =
2425ed0d50c3Schristos out_sections[index]->find_relaxed_input_section(this, index);
2426ed0d50c3Schristos gold_assert(poris != NULL);
2427ed0d50c3Schristos output_address = poris->address();
2428ed0d50c3Schristos }
2429ed0d50c3Schristos
2430ed0d50c3Schristos // Get the relocations.
2431ed0d50c3Schristos const unsigned char* prelocs = this->get_view(shdr.get_sh_offset(),
2432ed0d50c3Schristos shdr.get_sh_size(),
2433ed0d50c3Schristos true, false);
2434ed0d50c3Schristos
2435ed0d50c3Schristos // Get the section contents.
2436ed0d50c3Schristos section_size_type input_view_size = 0;
2437ed0d50c3Schristos const unsigned char* input_view =
2438ed0d50c3Schristos this->section_contents(index, &input_view_size, false);
2439ed0d50c3Schristos
2440ed0d50c3Schristos relinfo.reloc_shndx = i;
2441ed0d50c3Schristos relinfo.data_shndx = index;
2442ed0d50c3Schristos unsigned int sh_type = shdr.get_sh_type();
2443ed0d50c3Schristos unsigned int reloc_size;
2444ed0d50c3Schristos gold_assert (sh_type == elfcpp::SHT_RELA);
2445ed0d50c3Schristos reloc_size = elfcpp::Elf_sizes<size>::rela_size;
2446ed0d50c3Schristos
2447ed0d50c3Schristos Output_section* os = out_sections[index];
2448ed0d50c3Schristos target->scan_section_for_stubs(&relinfo, sh_type, prelocs,
2449ed0d50c3Schristos shdr.get_sh_size() / reloc_size,
2450ed0d50c3Schristos os,
2451ed0d50c3Schristos output_offset == invalid_address,
2452ed0d50c3Schristos input_view, output_address,
2453ed0d50c3Schristos input_view_size);
2454ed0d50c3Schristos }
2455ed0d50c3Schristos }
2456ed0d50c3Schristos }
2457ed0d50c3Schristos
2458ed0d50c3Schristos
2459ed0d50c3Schristos // A class to wrap an ordinary input section containing executable code.
2460ed0d50c3Schristos
2461ed0d50c3Schristos template<int size, bool big_endian>
2462ed0d50c3Schristos class AArch64_input_section : public Output_relaxed_input_section
2463ed0d50c3Schristos {
2464ed0d50c3Schristos public:
2465ed0d50c3Schristos typedef Stub_table<size, big_endian> The_stub_table;
2466ed0d50c3Schristos
AArch64_input_section(Relobj * relobj,unsigned int shndx)2467ed0d50c3Schristos AArch64_input_section(Relobj* relobj, unsigned int shndx)
2468ed0d50c3Schristos : Output_relaxed_input_section(relobj, shndx, 1),
2469ed0d50c3Schristos stub_table_(NULL),
2470ed0d50c3Schristos original_contents_(NULL), original_size_(0),
2471ed0d50c3Schristos original_addralign_(1)
2472ed0d50c3Schristos { }
2473ed0d50c3Schristos
~AArch64_input_section()2474ed0d50c3Schristos ~AArch64_input_section()
2475ed0d50c3Schristos { delete[] this->original_contents_; }
2476ed0d50c3Schristos
2477ed0d50c3Schristos // Initialize.
2478ed0d50c3Schristos void
2479ed0d50c3Schristos init();
2480ed0d50c3Schristos
2481ed0d50c3Schristos // Set the stub_table.
2482ed0d50c3Schristos void
set_stub_table(The_stub_table * st)2483ed0d50c3Schristos set_stub_table(The_stub_table* st)
2484ed0d50c3Schristos { this->stub_table_ = st; }
2485ed0d50c3Schristos
2486ed0d50c3Schristos // Whether this is a stub table owner.
2487ed0d50c3Schristos bool
is_stub_table_owner() const2488ed0d50c3Schristos is_stub_table_owner() const
2489ed0d50c3Schristos { return this->stub_table_ != NULL && this->stub_table_->owner() == this; }
2490ed0d50c3Schristos
2491ed0d50c3Schristos // Return the original size of the section.
2492ed0d50c3Schristos uint32_t
original_size() const2493ed0d50c3Schristos original_size() const
2494ed0d50c3Schristos { return this->original_size_; }
2495ed0d50c3Schristos
2496ed0d50c3Schristos // Return the stub table.
2497ed0d50c3Schristos The_stub_table*
stub_table()2498ed0d50c3Schristos stub_table()
2499ed0d50c3Schristos { return stub_table_; }
2500ed0d50c3Schristos
2501ed0d50c3Schristos protected:
2502ed0d50c3Schristos // Write out this input section.
2503ed0d50c3Schristos void
2504ed0d50c3Schristos do_write(Output_file*);
2505ed0d50c3Schristos
2506ed0d50c3Schristos // Return required alignment of this.
2507ed0d50c3Schristos uint64_t
do_addralign() const2508ed0d50c3Schristos do_addralign() const
2509ed0d50c3Schristos {
2510ed0d50c3Schristos if (this->is_stub_table_owner())
2511ed0d50c3Schristos return std::max(this->stub_table_->addralign(),
2512ed0d50c3Schristos static_cast<uint64_t>(this->original_addralign_));
2513ed0d50c3Schristos else
2514ed0d50c3Schristos return this->original_addralign_;
2515ed0d50c3Schristos }
2516ed0d50c3Schristos
2517ed0d50c3Schristos // Finalize data size.
2518ed0d50c3Schristos void
2519ed0d50c3Schristos set_final_data_size();
2520ed0d50c3Schristos
2521ed0d50c3Schristos // Reset address and file offset.
2522ed0d50c3Schristos void
2523ed0d50c3Schristos do_reset_address_and_file_offset();
2524ed0d50c3Schristos
2525ed0d50c3Schristos // Output offset.
2526ed0d50c3Schristos bool
do_output_offset(const Relobj * object,unsigned int shndx,section_offset_type offset,section_offset_type * poutput) const2527ed0d50c3Schristos do_output_offset(const Relobj* object, unsigned int shndx,
2528ed0d50c3Schristos section_offset_type offset,
2529ed0d50c3Schristos section_offset_type* poutput) const
2530ed0d50c3Schristos {
2531ed0d50c3Schristos if ((object == this->relobj())
2532ed0d50c3Schristos && (shndx == this->shndx())
2533ed0d50c3Schristos && (offset >= 0)
2534ed0d50c3Schristos && (offset <=
2535ed0d50c3Schristos convert_types<section_offset_type, uint32_t>(this->original_size_)))
2536ed0d50c3Schristos {
2537ed0d50c3Schristos *poutput = offset;
2538ed0d50c3Schristos return true;
2539ed0d50c3Schristos }
2540ed0d50c3Schristos else
2541ed0d50c3Schristos return false;
2542ed0d50c3Schristos }
2543ed0d50c3Schristos
2544ed0d50c3Schristos private:
2545ed0d50c3Schristos // Copying is not allowed.
2546ed0d50c3Schristos AArch64_input_section(const AArch64_input_section&);
2547ed0d50c3Schristos AArch64_input_section& operator=(const AArch64_input_section&);
2548ed0d50c3Schristos
2549ed0d50c3Schristos // The relocation stubs.
2550ed0d50c3Schristos The_stub_table* stub_table_;
2551ed0d50c3Schristos // Original section contents. We have to make a copy here since the file
2552ed0d50c3Schristos // containing the original section may not be locked when we need to access
2553ed0d50c3Schristos // the contents.
2554ed0d50c3Schristos unsigned char* original_contents_;
2555ed0d50c3Schristos // Section size of the original input section.
2556ed0d50c3Schristos uint32_t original_size_;
2557ed0d50c3Schristos // Address alignment of the original input section.
2558ed0d50c3Schristos uint32_t original_addralign_;
2559ed0d50c3Schristos }; // End of AArch64_input_section
2560ed0d50c3Schristos
2561ed0d50c3Schristos
2562ed0d50c3Schristos // Finalize data size.
2563ed0d50c3Schristos
2564ed0d50c3Schristos template<int size, bool big_endian>
2565ed0d50c3Schristos void
set_final_data_size()2566ed0d50c3Schristos AArch64_input_section<size, big_endian>::set_final_data_size()
2567ed0d50c3Schristos {
2568ed0d50c3Schristos off_t off = convert_types<off_t, uint64_t>(this->original_size_);
2569ed0d50c3Schristos
2570ed0d50c3Schristos if (this->is_stub_table_owner())
2571ed0d50c3Schristos {
2572ed0d50c3Schristos this->stub_table_->finalize_data_size();
2573ed0d50c3Schristos off = align_address(off, this->stub_table_->addralign());
2574ed0d50c3Schristos off += this->stub_table_->data_size();
2575ed0d50c3Schristos }
2576ed0d50c3Schristos this->set_data_size(off);
2577ed0d50c3Schristos }
2578ed0d50c3Schristos
2579ed0d50c3Schristos
2580ed0d50c3Schristos // Reset address and file offset.
2581ed0d50c3Schristos
2582ed0d50c3Schristos template<int size, bool big_endian>
2583ed0d50c3Schristos void
do_reset_address_and_file_offset()2584ed0d50c3Schristos AArch64_input_section<size, big_endian>::do_reset_address_and_file_offset()
2585ed0d50c3Schristos {
2586ed0d50c3Schristos // Size of the original input section contents.
2587ed0d50c3Schristos off_t off = convert_types<off_t, uint64_t>(this->original_size_);
2588ed0d50c3Schristos
2589ed0d50c3Schristos // If this is a stub table owner, account for the stub table size.
2590ed0d50c3Schristos if (this->is_stub_table_owner())
2591ed0d50c3Schristos {
2592ed0d50c3Schristos The_stub_table* stub_table = this->stub_table_;
2593ed0d50c3Schristos
2594ed0d50c3Schristos // Reset the stub table's address and file offset. The
2595ed0d50c3Schristos // current data size for child will be updated after that.
2596ed0d50c3Schristos stub_table_->reset_address_and_file_offset();
2597ed0d50c3Schristos off = align_address(off, stub_table_->addralign());
2598ed0d50c3Schristos off += stub_table->current_data_size();
2599ed0d50c3Schristos }
2600ed0d50c3Schristos
2601ed0d50c3Schristos this->set_current_data_size(off);
2602ed0d50c3Schristos }
2603ed0d50c3Schristos
2604ed0d50c3Schristos
2605ed0d50c3Schristos // Initialize an Arm_input_section.
2606ed0d50c3Schristos
2607ed0d50c3Schristos template<int size, bool big_endian>
2608ed0d50c3Schristos void
init()2609ed0d50c3Schristos AArch64_input_section<size, big_endian>::init()
2610ed0d50c3Schristos {
2611ed0d50c3Schristos Relobj* relobj = this->relobj();
2612ed0d50c3Schristos unsigned int shndx = this->shndx();
2613ed0d50c3Schristos
2614ed0d50c3Schristos // We have to cache original size, alignment and contents to avoid locking
2615ed0d50c3Schristos // the original file.
2616ed0d50c3Schristos this->original_addralign_ =
2617ed0d50c3Schristos convert_types<uint32_t, uint64_t>(relobj->section_addralign(shndx));
2618ed0d50c3Schristos
2619ed0d50c3Schristos // This is not efficient but we expect only a small number of relaxed
2620ed0d50c3Schristos // input sections for stubs.
2621ed0d50c3Schristos section_size_type section_size;
2622ed0d50c3Schristos const unsigned char* section_contents =
2623ed0d50c3Schristos relobj->section_contents(shndx, §ion_size, false);
2624ed0d50c3Schristos this->original_size_ =
2625ed0d50c3Schristos convert_types<uint32_t, uint64_t>(relobj->section_size(shndx));
2626ed0d50c3Schristos
2627ed0d50c3Schristos gold_assert(this->original_contents_ == NULL);
2628ed0d50c3Schristos this->original_contents_ = new unsigned char[section_size];
2629ed0d50c3Schristos memcpy(this->original_contents_, section_contents, section_size);
2630ed0d50c3Schristos
2631ed0d50c3Schristos // We want to make this look like the original input section after
2632ed0d50c3Schristos // output sections are finalized.
2633ed0d50c3Schristos Output_section* os = relobj->output_section(shndx);
2634ed0d50c3Schristos off_t offset = relobj->output_section_offset(shndx);
2635ed0d50c3Schristos gold_assert(os != NULL && !relobj->is_output_section_offset_invalid(shndx));
2636ed0d50c3Schristos this->set_address(os->address() + offset);
2637ed0d50c3Schristos this->set_file_offset(os->offset() + offset);
2638ed0d50c3Schristos this->set_current_data_size(this->original_size_);
2639ed0d50c3Schristos this->finalize_data_size();
2640ed0d50c3Schristos }
2641ed0d50c3Schristos
2642ed0d50c3Schristos
2643ed0d50c3Schristos // Write data to output file.
2644ed0d50c3Schristos
2645ed0d50c3Schristos template<int size, bool big_endian>
2646ed0d50c3Schristos void
do_write(Output_file * of)2647ed0d50c3Schristos AArch64_input_section<size, big_endian>::do_write(Output_file* of)
2648ed0d50c3Schristos {
2649ed0d50c3Schristos // We have to write out the original section content.
2650ed0d50c3Schristos gold_assert(this->original_contents_ != NULL);
2651ed0d50c3Schristos of->write(this->offset(), this->original_contents_,
2652ed0d50c3Schristos this->original_size_);
2653ed0d50c3Schristos
2654ed0d50c3Schristos // If this owns a stub table and it is not empty, write it.
2655ed0d50c3Schristos if (this->is_stub_table_owner() && !this->stub_table_->empty())
2656ed0d50c3Schristos this->stub_table_->write(of);
2657ed0d50c3Schristos }
2658ed0d50c3Schristos
2659ed0d50c3Schristos
2660ed0d50c3Schristos // Arm output section class. This is defined mainly to add a number of stub
2661ed0d50c3Schristos // generation methods.
2662ed0d50c3Schristos
2663ed0d50c3Schristos template<int size, bool big_endian>
2664ed0d50c3Schristos class AArch64_output_section : public Output_section
2665ed0d50c3Schristos {
2666ed0d50c3Schristos public:
2667ed0d50c3Schristos typedef Target_aarch64<size, big_endian> The_target_aarch64;
2668ed0d50c3Schristos typedef AArch64_relobj<size, big_endian> The_aarch64_relobj;
2669ed0d50c3Schristos typedef Stub_table<size, big_endian> The_stub_table;
2670ed0d50c3Schristos typedef AArch64_input_section<size, big_endian> The_aarch64_input_section;
2671ed0d50c3Schristos
2672ed0d50c3Schristos public:
AArch64_output_section(const char * name,elfcpp::Elf_Word type,elfcpp::Elf_Xword flags)2673ed0d50c3Schristos AArch64_output_section(const char* name, elfcpp::Elf_Word type,
2674ed0d50c3Schristos elfcpp::Elf_Xword flags)
2675ed0d50c3Schristos : Output_section(name, type, flags)
2676ed0d50c3Schristos { }
2677ed0d50c3Schristos
~AArch64_output_section()2678ed0d50c3Schristos ~AArch64_output_section() {}
2679ed0d50c3Schristos
2680ed0d50c3Schristos // Group input sections for stub generation.
2681ed0d50c3Schristos void
2682ed0d50c3Schristos group_sections(section_size_type, bool, Target_aarch64<size, big_endian>*,
2683ed0d50c3Schristos const Task*);
2684ed0d50c3Schristos
2685ed0d50c3Schristos private:
2686ed0d50c3Schristos typedef Output_section::Input_section Input_section;
2687ed0d50c3Schristos typedef Output_section::Input_section_list Input_section_list;
2688ed0d50c3Schristos
2689ed0d50c3Schristos // Create a stub group.
2690ed0d50c3Schristos void
2691ed0d50c3Schristos create_stub_group(Input_section_list::const_iterator,
2692ed0d50c3Schristos Input_section_list::const_iterator,
2693ed0d50c3Schristos Input_section_list::const_iterator,
2694ed0d50c3Schristos The_target_aarch64*,
2695ed0d50c3Schristos std::vector<Output_relaxed_input_section*>&,
2696ed0d50c3Schristos const Task*);
2697ed0d50c3Schristos }; // End of AArch64_output_section
2698ed0d50c3Schristos
2699ed0d50c3Schristos
2700ed0d50c3Schristos // Create a stub group for input sections from FIRST to LAST. OWNER points to
2701ed0d50c3Schristos // the input section that will be the owner of the stub table.
2702ed0d50c3Schristos
2703ed0d50c3Schristos template<int size, bool big_endian> void
create_stub_group(Input_section_list::const_iterator first,Input_section_list::const_iterator last,Input_section_list::const_iterator owner,The_target_aarch64 * target,std::vector<Output_relaxed_input_section * > & new_relaxed_sections,const Task * task)2704ed0d50c3Schristos AArch64_output_section<size, big_endian>::create_stub_group(
2705ed0d50c3Schristos Input_section_list::const_iterator first,
2706ed0d50c3Schristos Input_section_list::const_iterator last,
2707ed0d50c3Schristos Input_section_list::const_iterator owner,
2708ed0d50c3Schristos The_target_aarch64* target,
2709ed0d50c3Schristos std::vector<Output_relaxed_input_section*>& new_relaxed_sections,
2710ed0d50c3Schristos const Task* task)
2711ed0d50c3Schristos {
2712ed0d50c3Schristos // Currently we convert ordinary input sections into relaxed sections only
2713ed0d50c3Schristos // at this point.
2714ed0d50c3Schristos The_aarch64_input_section* input_section;
2715ed0d50c3Schristos if (owner->is_relaxed_input_section())
2716ed0d50c3Schristos gold_unreachable();
2717ed0d50c3Schristos else
2718ed0d50c3Schristos {
2719ed0d50c3Schristos gold_assert(owner->is_input_section());
2720ed0d50c3Schristos // Create a new relaxed input section. We need to lock the original
2721ed0d50c3Schristos // file.
2722ed0d50c3Schristos Task_lock_obj<Object> tl(task, owner->relobj());
2723ed0d50c3Schristos input_section =
2724ed0d50c3Schristos target->new_aarch64_input_section(owner->relobj(), owner->shndx());
2725ed0d50c3Schristos new_relaxed_sections.push_back(input_section);
2726ed0d50c3Schristos }
2727ed0d50c3Schristos
2728ed0d50c3Schristos // Create a stub table.
2729ed0d50c3Schristos The_stub_table* stub_table =
2730ed0d50c3Schristos target->new_stub_table(input_section);
2731ed0d50c3Schristos
2732ed0d50c3Schristos input_section->set_stub_table(stub_table);
2733ed0d50c3Schristos
2734ed0d50c3Schristos Input_section_list::const_iterator p = first;
2735ed0d50c3Schristos // Look for input sections or relaxed input sections in [first ... last].
2736ed0d50c3Schristos do
2737ed0d50c3Schristos {
2738ed0d50c3Schristos if (p->is_input_section() || p->is_relaxed_input_section())
2739ed0d50c3Schristos {
2740ed0d50c3Schristos // The stub table information for input sections live
2741ed0d50c3Schristos // in their objects.
2742ed0d50c3Schristos The_aarch64_relobj* aarch64_relobj =
2743ed0d50c3Schristos static_cast<The_aarch64_relobj*>(p->relobj());
2744ed0d50c3Schristos aarch64_relobj->set_stub_table(p->shndx(), stub_table);
2745ed0d50c3Schristos }
2746ed0d50c3Schristos }
2747ed0d50c3Schristos while (p++ != last);
2748ed0d50c3Schristos }
2749ed0d50c3Schristos
2750ed0d50c3Schristos
2751ed0d50c3Schristos // Group input sections for stub generation. GROUP_SIZE is roughly the limit of
2752ed0d50c3Schristos // stub groups. We grow a stub group by adding input section until the size is
2753ed0d50c3Schristos // just below GROUP_SIZE. The last input section will be converted into a stub
2754ed0d50c3Schristos // table owner. If STUB_ALWAYS_AFTER_BRANCH is false, we also add input sectiond
2755ed0d50c3Schristos // after the stub table, effectively doubling the group size.
2756ed0d50c3Schristos //
2757ed0d50c3Schristos // This is similar to the group_sections() function in elf32-arm.c but is
2758ed0d50c3Schristos // implemented differently.
2759ed0d50c3Schristos
2760ed0d50c3Schristos template<int size, bool big_endian>
group_sections(section_size_type group_size,bool stubs_always_after_branch,Target_aarch64<size,big_endian> * target,const Task * task)2761ed0d50c3Schristos void AArch64_output_section<size, big_endian>::group_sections(
2762ed0d50c3Schristos section_size_type group_size,
2763ed0d50c3Schristos bool stubs_always_after_branch,
2764ed0d50c3Schristos Target_aarch64<size, big_endian>* target,
2765ed0d50c3Schristos const Task* task)
2766ed0d50c3Schristos {
2767ed0d50c3Schristos typedef enum
2768ed0d50c3Schristos {
2769ed0d50c3Schristos NO_GROUP,
2770ed0d50c3Schristos FINDING_STUB_SECTION,
2771ed0d50c3Schristos HAS_STUB_SECTION
2772ed0d50c3Schristos } State;
2773ed0d50c3Schristos
2774ed0d50c3Schristos std::vector<Output_relaxed_input_section*> new_relaxed_sections;
2775ed0d50c3Schristos
2776ed0d50c3Schristos State state = NO_GROUP;
2777ed0d50c3Schristos section_size_type off = 0;
2778ed0d50c3Schristos section_size_type group_begin_offset = 0;
2779ed0d50c3Schristos section_size_type group_end_offset = 0;
2780ed0d50c3Schristos section_size_type stub_table_end_offset = 0;
2781ed0d50c3Schristos Input_section_list::const_iterator group_begin =
2782ed0d50c3Schristos this->input_sections().end();
2783ed0d50c3Schristos Input_section_list::const_iterator stub_table =
2784ed0d50c3Schristos this->input_sections().end();
2785ed0d50c3Schristos Input_section_list::const_iterator group_end = this->input_sections().end();
2786ed0d50c3Schristos for (Input_section_list::const_iterator p = this->input_sections().begin();
2787ed0d50c3Schristos p != this->input_sections().end();
2788ed0d50c3Schristos ++p)
2789ed0d50c3Schristos {
2790ed0d50c3Schristos section_size_type section_begin_offset =
2791ed0d50c3Schristos align_address(off, p->addralign());
2792ed0d50c3Schristos section_size_type section_end_offset =
2793ed0d50c3Schristos section_begin_offset + p->data_size();
2794ed0d50c3Schristos
2795ed0d50c3Schristos // Check to see if we should group the previously seen sections.
2796ed0d50c3Schristos switch (state)
2797ed0d50c3Schristos {
2798ed0d50c3Schristos case NO_GROUP:
2799ed0d50c3Schristos break;
2800ed0d50c3Schristos
2801ed0d50c3Schristos case FINDING_STUB_SECTION:
2802ed0d50c3Schristos // Adding this section makes the group larger than GROUP_SIZE.
2803ed0d50c3Schristos if (section_end_offset - group_begin_offset >= group_size)
2804ed0d50c3Schristos {
2805ed0d50c3Schristos if (stubs_always_after_branch)
2806ed0d50c3Schristos {
2807ed0d50c3Schristos gold_assert(group_end != this->input_sections().end());
2808ed0d50c3Schristos this->create_stub_group(group_begin, group_end, group_end,
2809ed0d50c3Schristos target, new_relaxed_sections,
2810ed0d50c3Schristos task);
2811ed0d50c3Schristos state = NO_GROUP;
2812ed0d50c3Schristos }
2813ed0d50c3Schristos else
2814ed0d50c3Schristos {
2815ed0d50c3Schristos // Input sections up to stub_group_size bytes after the stub
2816ed0d50c3Schristos // table can be handled by it too.
2817ed0d50c3Schristos state = HAS_STUB_SECTION;
2818ed0d50c3Schristos stub_table = group_end;
2819ed0d50c3Schristos stub_table_end_offset = group_end_offset;
2820ed0d50c3Schristos }
2821ed0d50c3Schristos }
2822ed0d50c3Schristos break;
2823ed0d50c3Schristos
2824ed0d50c3Schristos case HAS_STUB_SECTION:
2825ed0d50c3Schristos // Adding this section makes the post stub-section group larger
2826ed0d50c3Schristos // than GROUP_SIZE.
2827ed0d50c3Schristos gold_unreachable();
2828ed0d50c3Schristos // NOT SUPPORTED YET. For completeness only.
2829ed0d50c3Schristos if (section_end_offset - stub_table_end_offset >= group_size)
2830ed0d50c3Schristos {
2831ed0d50c3Schristos gold_assert(group_end != this->input_sections().end());
2832ed0d50c3Schristos this->create_stub_group(group_begin, group_end, stub_table,
2833ed0d50c3Schristos target, new_relaxed_sections, task);
2834ed0d50c3Schristos state = NO_GROUP;
2835ed0d50c3Schristos }
2836ed0d50c3Schristos break;
2837ed0d50c3Schristos
2838ed0d50c3Schristos default:
2839ed0d50c3Schristos gold_unreachable();
2840ed0d50c3Schristos }
2841ed0d50c3Schristos
2842ed0d50c3Schristos // If we see an input section and currently there is no group, start
2843ed0d50c3Schristos // a new one. Skip any empty sections. We look at the data size
2844ed0d50c3Schristos // instead of calling p->relobj()->section_size() to avoid locking.
2845ed0d50c3Schristos if ((p->is_input_section() || p->is_relaxed_input_section())
2846ed0d50c3Schristos && (p->data_size() != 0))
2847ed0d50c3Schristos {
2848ed0d50c3Schristos if (state == NO_GROUP)
2849ed0d50c3Schristos {
2850ed0d50c3Schristos state = FINDING_STUB_SECTION;
2851ed0d50c3Schristos group_begin = p;
2852ed0d50c3Schristos group_begin_offset = section_begin_offset;
2853ed0d50c3Schristos }
2854ed0d50c3Schristos
2855ed0d50c3Schristos // Keep track of the last input section seen.
2856ed0d50c3Schristos group_end = p;
2857ed0d50c3Schristos group_end_offset = section_end_offset;
2858ed0d50c3Schristos }
2859ed0d50c3Schristos
2860ed0d50c3Schristos off = section_end_offset;
2861ed0d50c3Schristos }
2862ed0d50c3Schristos
2863ed0d50c3Schristos // Create a stub group for any ungrouped sections.
2864ed0d50c3Schristos if (state == FINDING_STUB_SECTION || state == HAS_STUB_SECTION)
2865ed0d50c3Schristos {
2866ed0d50c3Schristos gold_assert(group_end != this->input_sections().end());
2867ed0d50c3Schristos this->create_stub_group(group_begin, group_end,
2868ed0d50c3Schristos (state == FINDING_STUB_SECTION
2869ed0d50c3Schristos ? group_end
2870ed0d50c3Schristos : stub_table),
2871ed0d50c3Schristos target, new_relaxed_sections, task);
2872ed0d50c3Schristos }
2873ed0d50c3Schristos
2874ed0d50c3Schristos if (!new_relaxed_sections.empty())
2875ed0d50c3Schristos this->convert_input_sections_to_relaxed_sections(new_relaxed_sections);
2876ed0d50c3Schristos
2877ed0d50c3Schristos // Update the section offsets
2878ed0d50c3Schristos for (size_t i = 0; i < new_relaxed_sections.size(); ++i)
2879ed0d50c3Schristos {
2880ed0d50c3Schristos The_aarch64_relobj* relobj = static_cast<The_aarch64_relobj*>(
2881ed0d50c3Schristos new_relaxed_sections[i]->relobj());
2882ed0d50c3Schristos unsigned int shndx = new_relaxed_sections[i]->shndx();
2883ed0d50c3Schristos // Tell AArch64_relobj that this input section is converted.
2884ed0d50c3Schristos relobj->convert_input_section_to_relaxed_section(shndx);
2885ed0d50c3Schristos }
2886ed0d50c3Schristos } // End of AArch64_output_section::group_sections
2887ed0d50c3Schristos
2888ed0d50c3Schristos
2889ed0d50c3Schristos AArch64_reloc_property_table* aarch64_reloc_property_table = NULL;
2890ed0d50c3Schristos
2891ed0d50c3Schristos
2892ed0d50c3Schristos // The aarch64 target class.
2893ed0d50c3Schristos // See the ABI at
2894ed0d50c3Schristos // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf
2895ed0d50c3Schristos template<int size, bool big_endian>
2896ed0d50c3Schristos class Target_aarch64 : public Sized_target<size, big_endian>
2897ed0d50c3Schristos {
2898ed0d50c3Schristos public:
2899ed0d50c3Schristos typedef Target_aarch64<size, big_endian> This;
2900ed0d50c3Schristos typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>
2901ed0d50c3Schristos Reloc_section;
2902ed0d50c3Schristos typedef Relocate_info<size, big_endian> The_relocate_info;
2903ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
2904ed0d50c3Schristos typedef AArch64_relobj<size, big_endian> The_aarch64_relobj;
2905ed0d50c3Schristos typedef Reloc_stub<size, big_endian> The_reloc_stub;
2906ed0d50c3Schristos typedef Erratum_stub<size, big_endian> The_erratum_stub;
2907ed0d50c3Schristos typedef typename Reloc_stub<size, big_endian>::Key The_reloc_stub_key;
2908ed0d50c3Schristos typedef Stub_table<size, big_endian> The_stub_table;
2909ed0d50c3Schristos typedef std::vector<The_stub_table*> Stub_table_list;
2910ed0d50c3Schristos typedef typename Stub_table_list::iterator Stub_table_iterator;
2911ed0d50c3Schristos typedef AArch64_input_section<size, big_endian> The_aarch64_input_section;
2912ed0d50c3Schristos typedef AArch64_output_section<size, big_endian> The_aarch64_output_section;
2913ed0d50c3Schristos typedef Unordered_map<Section_id,
2914ed0d50c3Schristos AArch64_input_section<size, big_endian>*,
2915ed0d50c3Schristos Section_id_hash> AArch64_input_section_map;
2916ed0d50c3Schristos typedef AArch64_insn_utilities<big_endian> Insn_utilities;
2917ed0d50c3Schristos const static int TCB_SIZE = size / 8 * 2;
2918ed0d50c3Schristos
Target_aarch64(const Target::Target_info * info=& aarch64_info)2919ed0d50c3Schristos Target_aarch64(const Target::Target_info* info = &aarch64_info)
2920ed0d50c3Schristos : Sized_target<size, big_endian>(info),
2921ed0d50c3Schristos got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
2922ed0d50c3Schristos got_tlsdesc_(NULL), global_offset_table_(NULL), rela_dyn_(NULL),
2923ed0d50c3Schristos rela_irelative_(NULL), copy_relocs_(elfcpp::R_AARCH64_COPY),
2924ed0d50c3Schristos got_mod_index_offset_(-1U),
2925ed0d50c3Schristos tlsdesc_reloc_info_(), tls_base_symbol_defined_(false),
2926ed0d50c3Schristos stub_tables_(), stub_group_size_(0), aarch64_input_section_map_()
2927ed0d50c3Schristos { }
2928ed0d50c3Schristos
2929ed0d50c3Schristos // Scan the relocations to determine unreferenced sections for
2930ed0d50c3Schristos // garbage collection.
2931ed0d50c3Schristos void
2932ed0d50c3Schristos gc_process_relocs(Symbol_table* symtab,
2933ed0d50c3Schristos Layout* layout,
2934ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object,
2935ed0d50c3Schristos unsigned int data_shndx,
2936ed0d50c3Schristos unsigned int sh_type,
2937ed0d50c3Schristos const unsigned char* prelocs,
2938ed0d50c3Schristos size_t reloc_count,
2939ed0d50c3Schristos Output_section* output_section,
2940ed0d50c3Schristos bool needs_special_offset_handling,
2941ed0d50c3Schristos size_t local_symbol_count,
2942ed0d50c3Schristos const unsigned char* plocal_symbols);
2943ed0d50c3Schristos
2944ed0d50c3Schristos // Scan the relocations to look for symbol adjustments.
2945ed0d50c3Schristos void
2946ed0d50c3Schristos scan_relocs(Symbol_table* symtab,
2947ed0d50c3Schristos Layout* layout,
2948ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object,
2949ed0d50c3Schristos unsigned int data_shndx,
2950ed0d50c3Schristos unsigned int sh_type,
2951ed0d50c3Schristos const unsigned char* prelocs,
2952ed0d50c3Schristos size_t reloc_count,
2953ed0d50c3Schristos Output_section* output_section,
2954ed0d50c3Schristos bool needs_special_offset_handling,
2955ed0d50c3Schristos size_t local_symbol_count,
2956ed0d50c3Schristos const unsigned char* plocal_symbols);
2957ed0d50c3Schristos
2958ed0d50c3Schristos // Finalize the sections.
2959ed0d50c3Schristos void
2960ed0d50c3Schristos do_finalize_sections(Layout*, const Input_objects*, Symbol_table*);
2961ed0d50c3Schristos
2962ed0d50c3Schristos // Return the value to use for a dynamic which requires special
2963ed0d50c3Schristos // treatment.
2964ed0d50c3Schristos uint64_t
2965ed0d50c3Schristos do_dynsym_value(const Symbol*) const;
2966ed0d50c3Schristos
2967ed0d50c3Schristos // Relocate a section.
2968ed0d50c3Schristos void
2969ed0d50c3Schristos relocate_section(const Relocate_info<size, big_endian>*,
2970ed0d50c3Schristos unsigned int sh_type,
2971ed0d50c3Schristos const unsigned char* prelocs,
2972ed0d50c3Schristos size_t reloc_count,
2973ed0d50c3Schristos Output_section* output_section,
2974ed0d50c3Schristos bool needs_special_offset_handling,
2975ed0d50c3Schristos unsigned char* view,
2976ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr view_address,
2977ed0d50c3Schristos section_size_type view_size,
2978ed0d50c3Schristos const Reloc_symbol_changes*);
2979ed0d50c3Schristos
2980ed0d50c3Schristos // Scan the relocs during a relocatable link.
2981ed0d50c3Schristos void
2982ed0d50c3Schristos scan_relocatable_relocs(Symbol_table* symtab,
2983ed0d50c3Schristos Layout* layout,
2984ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object,
2985ed0d50c3Schristos unsigned int data_shndx,
2986ed0d50c3Schristos unsigned int sh_type,
2987ed0d50c3Schristos const unsigned char* prelocs,
2988ed0d50c3Schristos size_t reloc_count,
2989ed0d50c3Schristos Output_section* output_section,
2990ed0d50c3Schristos bool needs_special_offset_handling,
2991ed0d50c3Schristos size_t local_symbol_count,
2992ed0d50c3Schristos const unsigned char* plocal_symbols,
2993ed0d50c3Schristos Relocatable_relocs*);
2994ed0d50c3Schristos
2995ed0d50c3Schristos // Scan the relocs for --emit-relocs.
2996ed0d50c3Schristos void
2997ed0d50c3Schristos emit_relocs_scan(Symbol_table* symtab,
2998ed0d50c3Schristos Layout* layout,
2999ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object,
3000ed0d50c3Schristos unsigned int data_shndx,
3001ed0d50c3Schristos unsigned int sh_type,
3002ed0d50c3Schristos const unsigned char* prelocs,
3003ed0d50c3Schristos size_t reloc_count,
3004ed0d50c3Schristos Output_section* output_section,
3005ed0d50c3Schristos bool needs_special_offset_handling,
3006ed0d50c3Schristos size_t local_symbol_count,
3007ed0d50c3Schristos const unsigned char* plocal_syms,
3008ed0d50c3Schristos Relocatable_relocs* rr);
3009ed0d50c3Schristos
3010ed0d50c3Schristos // Relocate a section during a relocatable link.
3011ed0d50c3Schristos void
3012ed0d50c3Schristos relocate_relocs(
3013ed0d50c3Schristos const Relocate_info<size, big_endian>*,
3014ed0d50c3Schristos unsigned int sh_type,
3015ed0d50c3Schristos const unsigned char* prelocs,
3016ed0d50c3Schristos size_t reloc_count,
3017ed0d50c3Schristos Output_section* output_section,
3018ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
3019ed0d50c3Schristos unsigned char* view,
3020ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr view_address,
3021ed0d50c3Schristos section_size_type view_size,
3022ed0d50c3Schristos unsigned char* reloc_view,
3023ed0d50c3Schristos section_size_type reloc_view_size);
3024ed0d50c3Schristos
3025ed0d50c3Schristos // Return the symbol index to use for a target specific relocation.
3026ed0d50c3Schristos // The only target specific relocation is R_AARCH64_TLSDESC for a
3027ed0d50c3Schristos // local symbol, which is an absolute reloc.
3028ed0d50c3Schristos unsigned int
do_reloc_symbol_index(void *,unsigned int r_type) const3029ed0d50c3Schristos do_reloc_symbol_index(void*, unsigned int r_type) const
3030ed0d50c3Schristos {
3031ed0d50c3Schristos gold_assert(r_type == elfcpp::R_AARCH64_TLSDESC);
3032ed0d50c3Schristos return 0;
3033ed0d50c3Schristos }
3034ed0d50c3Schristos
3035ed0d50c3Schristos // Return the addend to use for a target specific relocation.
3036ed0d50c3Schristos uint64_t
3037ed0d50c3Schristos do_reloc_addend(void* arg, unsigned int r_type, uint64_t addend) const;
3038ed0d50c3Schristos
3039ed0d50c3Schristos // Return the PLT section.
3040ed0d50c3Schristos uint64_t
do_plt_address_for_global(const Symbol * gsym) const3041ed0d50c3Schristos do_plt_address_for_global(const Symbol* gsym) const
3042ed0d50c3Schristos { return this->plt_section()->address_for_global(gsym); }
3043ed0d50c3Schristos
3044ed0d50c3Schristos uint64_t
do_plt_address_for_local(const Relobj * relobj,unsigned int symndx) const3045ed0d50c3Schristos do_plt_address_for_local(const Relobj* relobj, unsigned int symndx) const
3046ed0d50c3Schristos { return this->plt_section()->address_for_local(relobj, symndx); }
3047ed0d50c3Schristos
3048ed0d50c3Schristos // This function should be defined in targets that can use relocation
3049ed0d50c3Schristos // types to determine (implemented in local_reloc_may_be_function_pointer
3050ed0d50c3Schristos // and global_reloc_may_be_function_pointer)
3051ed0d50c3Schristos // if a function's pointer is taken. ICF uses this in safe mode to only
3052ed0d50c3Schristos // fold those functions whose pointer is defintely not taken.
3053ed0d50c3Schristos bool
do_can_check_for_function_pointers() const3054ed0d50c3Schristos do_can_check_for_function_pointers() const
3055ed0d50c3Schristos { return true; }
3056ed0d50c3Schristos
3057ed0d50c3Schristos // Return the number of entries in the PLT.
3058ed0d50c3Schristos unsigned int
3059ed0d50c3Schristos plt_entry_count() const;
3060ed0d50c3Schristos
3061ed0d50c3Schristos //Return the offset of the first non-reserved PLT entry.
3062ed0d50c3Schristos unsigned int
3063ed0d50c3Schristos first_plt_entry_offset() const;
3064ed0d50c3Schristos
3065ed0d50c3Schristos // Return the size of each PLT entry.
3066ed0d50c3Schristos unsigned int
3067ed0d50c3Schristos plt_entry_size() const;
3068ed0d50c3Schristos
3069ed0d50c3Schristos // Create a stub table.
3070ed0d50c3Schristos The_stub_table*
3071ed0d50c3Schristos new_stub_table(The_aarch64_input_section*);
3072ed0d50c3Schristos
3073ed0d50c3Schristos // Create an aarch64 input section.
3074ed0d50c3Schristos The_aarch64_input_section*
3075ed0d50c3Schristos new_aarch64_input_section(Relobj*, unsigned int);
3076ed0d50c3Schristos
3077ed0d50c3Schristos // Find an aarch64 input section instance for a given OBJ and SHNDX.
3078ed0d50c3Schristos The_aarch64_input_section*
3079ed0d50c3Schristos find_aarch64_input_section(Relobj*, unsigned int) const;
3080ed0d50c3Schristos
3081ed0d50c3Schristos // Return the thread control block size.
3082ed0d50c3Schristos unsigned int
tcb_size() const3083ed0d50c3Schristos tcb_size() const { return This::TCB_SIZE; }
3084ed0d50c3Schristos
3085ed0d50c3Schristos // Scan a section for stub generation.
3086ed0d50c3Schristos void
3087ed0d50c3Schristos scan_section_for_stubs(const Relocate_info<size, big_endian>*, unsigned int,
3088ed0d50c3Schristos const unsigned char*, size_t, Output_section*,
3089ed0d50c3Schristos bool, const unsigned char*,
3090ed0d50c3Schristos Address,
3091ed0d50c3Schristos section_size_type);
3092ed0d50c3Schristos
3093ed0d50c3Schristos // Scan a relocation section for stub.
3094ed0d50c3Schristos template<int sh_type>
3095ed0d50c3Schristos void
3096ed0d50c3Schristos scan_reloc_section_for_stubs(
3097ed0d50c3Schristos const The_relocate_info* relinfo,
3098ed0d50c3Schristos const unsigned char* prelocs,
3099ed0d50c3Schristos size_t reloc_count,
3100ed0d50c3Schristos Output_section* output_section,
3101ed0d50c3Schristos bool needs_special_offset_handling,
3102ed0d50c3Schristos const unsigned char* view,
3103ed0d50c3Schristos Address view_address,
3104ed0d50c3Schristos section_size_type);
3105ed0d50c3Schristos
310606324dcfSchristos // Relocate a single reloc stub.
3107ed0d50c3Schristos void
310806324dcfSchristos relocate_reloc_stub(The_reloc_stub*, const Relocate_info<size, big_endian>*,
3109ed0d50c3Schristos Output_section*, unsigned char*, Address,
3110ed0d50c3Schristos section_size_type);
3111ed0d50c3Schristos
3112ed0d50c3Schristos // Get the default AArch64 target.
3113ed0d50c3Schristos static This*
current_target()3114ed0d50c3Schristos current_target()
3115ed0d50c3Schristos {
3116ed0d50c3Schristos gold_assert(parameters->target().machine_code() == elfcpp::EM_AARCH64
3117ed0d50c3Schristos && parameters->target().get_size() == size
3118ed0d50c3Schristos && parameters->target().is_big_endian() == big_endian);
3119ed0d50c3Schristos return static_cast<This*>(parameters->sized_target<size, big_endian>());
3120ed0d50c3Schristos }
3121ed0d50c3Schristos
3122ed0d50c3Schristos
3123ed0d50c3Schristos // Scan erratum 843419 for a part of a section.
3124ed0d50c3Schristos void
3125ed0d50c3Schristos scan_erratum_843419_span(
3126ed0d50c3Schristos AArch64_relobj<size, big_endian>*,
3127ed0d50c3Schristos unsigned int,
3128ed0d50c3Schristos const section_size_type,
3129ed0d50c3Schristos const section_size_type,
3130ed0d50c3Schristos unsigned char*,
3131ed0d50c3Schristos Address);
3132ed0d50c3Schristos
3133ed0d50c3Schristos // Scan erratum 835769 for a part of a section.
3134ed0d50c3Schristos void
3135ed0d50c3Schristos scan_erratum_835769_span(
3136ed0d50c3Schristos AArch64_relobj<size, big_endian>*,
3137ed0d50c3Schristos unsigned int,
3138ed0d50c3Schristos const section_size_type,
3139ed0d50c3Schristos const section_size_type,
3140ed0d50c3Schristos unsigned char*,
3141ed0d50c3Schristos Address);
3142ed0d50c3Schristos
3143ed0d50c3Schristos protected:
3144ed0d50c3Schristos void
do_select_as_default_target()3145ed0d50c3Schristos do_select_as_default_target()
3146ed0d50c3Schristos {
3147ed0d50c3Schristos gold_assert(aarch64_reloc_property_table == NULL);
3148ed0d50c3Schristos aarch64_reloc_property_table = new AArch64_reloc_property_table();
3149ed0d50c3Schristos }
3150ed0d50c3Schristos
3151ed0d50c3Schristos // Add a new reloc argument, returning the index in the vector.
3152ed0d50c3Schristos size_t
add_tlsdesc_info(Sized_relobj_file<size,big_endian> * object,unsigned int r_sym)3153ed0d50c3Schristos add_tlsdesc_info(Sized_relobj_file<size, big_endian>* object,
3154ed0d50c3Schristos unsigned int r_sym)
3155ed0d50c3Schristos {
3156ed0d50c3Schristos this->tlsdesc_reloc_info_.push_back(Tlsdesc_info(object, r_sym));
3157ed0d50c3Schristos return this->tlsdesc_reloc_info_.size() - 1;
3158ed0d50c3Schristos }
3159ed0d50c3Schristos
3160ed0d50c3Schristos virtual Output_data_plt_aarch64<size, big_endian>*
do_make_data_plt(Layout * layout,Output_data_got_aarch64<size,big_endian> * got,Output_data_space * got_plt,Output_data_space * got_irelative)3161ed0d50c3Schristos do_make_data_plt(Layout* layout,
3162ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>* got,
3163ed0d50c3Schristos Output_data_space* got_plt,
3164ed0d50c3Schristos Output_data_space* got_irelative)
3165ed0d50c3Schristos {
3166ed0d50c3Schristos return new Output_data_plt_aarch64_standard<size, big_endian>(
3167ed0d50c3Schristos layout, got, got_plt, got_irelative);
3168ed0d50c3Schristos }
3169ed0d50c3Schristos
3170ed0d50c3Schristos
3171ed0d50c3Schristos // do_make_elf_object to override the same function in the base class.
3172ed0d50c3Schristos Object*
3173ed0d50c3Schristos do_make_elf_object(const std::string&, Input_file*, off_t,
3174ed0d50c3Schristos const elfcpp::Ehdr<size, big_endian>&);
3175ed0d50c3Schristos
3176ed0d50c3Schristos Output_data_plt_aarch64<size, big_endian>*
make_data_plt(Layout * layout,Output_data_got_aarch64<size,big_endian> * got,Output_data_space * got_plt,Output_data_space * got_irelative)3177ed0d50c3Schristos make_data_plt(Layout* layout,
3178ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>* got,
3179ed0d50c3Schristos Output_data_space* got_plt,
3180ed0d50c3Schristos Output_data_space* got_irelative)
3181ed0d50c3Schristos {
3182ed0d50c3Schristos return this->do_make_data_plt(layout, got, got_plt, got_irelative);
3183ed0d50c3Schristos }
3184ed0d50c3Schristos
3185ed0d50c3Schristos // We only need to generate stubs, and hence perform relaxation if we are
3186ed0d50c3Schristos // not doing relocatable linking.
3187ed0d50c3Schristos virtual bool
do_may_relax() const3188ed0d50c3Schristos do_may_relax() const
3189ed0d50c3Schristos { return !parameters->options().relocatable(); }
3190ed0d50c3Schristos
3191ed0d50c3Schristos // Relaxation hook. This is where we do stub generation.
3192ed0d50c3Schristos virtual bool
3193ed0d50c3Schristos do_relax(int, const Input_objects*, Symbol_table*, Layout*, const Task*);
3194ed0d50c3Schristos
3195ed0d50c3Schristos void
3196ed0d50c3Schristos group_sections(Layout* layout,
3197ed0d50c3Schristos section_size_type group_size,
3198ed0d50c3Schristos bool stubs_always_after_branch,
3199ed0d50c3Schristos const Task* task);
3200ed0d50c3Schristos
3201ed0d50c3Schristos void
3202ed0d50c3Schristos scan_reloc_for_stub(const The_relocate_info*, unsigned int,
3203ed0d50c3Schristos const Sized_symbol<size>*, unsigned int,
3204ed0d50c3Schristos const Symbol_value<size>*,
3205ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Swxword,
3206ed0d50c3Schristos Address Elf_Addr);
3207ed0d50c3Schristos
3208ed0d50c3Schristos // Make an output section.
3209ed0d50c3Schristos Output_section*
do_make_output_section(const char * name,elfcpp::Elf_Word type,elfcpp::Elf_Xword flags)3210ed0d50c3Schristos do_make_output_section(const char* name, elfcpp::Elf_Word type,
3211ed0d50c3Schristos elfcpp::Elf_Xword flags)
3212ed0d50c3Schristos { return new The_aarch64_output_section(name, type, flags); }
3213ed0d50c3Schristos
3214ed0d50c3Schristos private:
3215ed0d50c3Schristos // The class which scans relocations.
3216ed0d50c3Schristos class Scan
3217ed0d50c3Schristos {
3218ed0d50c3Schristos public:
Scan()3219ed0d50c3Schristos Scan()
3220ed0d50c3Schristos : issued_non_pic_error_(false)
3221ed0d50c3Schristos { }
3222ed0d50c3Schristos
3223ed0d50c3Schristos inline void
3224ed0d50c3Schristos local(Symbol_table* symtab, Layout* layout, Target_aarch64* target,
3225ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object,
3226ed0d50c3Schristos unsigned int data_shndx,
3227ed0d50c3Schristos Output_section* output_section,
3228ed0d50c3Schristos const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
3229ed0d50c3Schristos const elfcpp::Sym<size, big_endian>& lsym,
3230ed0d50c3Schristos bool is_discarded);
3231ed0d50c3Schristos
3232ed0d50c3Schristos inline void
3233ed0d50c3Schristos global(Symbol_table* symtab, Layout* layout, Target_aarch64* target,
3234ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object,
3235ed0d50c3Schristos unsigned int data_shndx,
3236ed0d50c3Schristos Output_section* output_section,
3237ed0d50c3Schristos const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
3238ed0d50c3Schristos Symbol* gsym);
3239ed0d50c3Schristos
3240ed0d50c3Schristos inline bool
3241ed0d50c3Schristos local_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
3242ed0d50c3Schristos Target_aarch64<size, big_endian>* ,
3243ed0d50c3Schristos Sized_relobj_file<size, big_endian>* ,
3244ed0d50c3Schristos unsigned int ,
3245ed0d50c3Schristos Output_section* ,
3246ed0d50c3Schristos const elfcpp::Rela<size, big_endian>& ,
3247ed0d50c3Schristos unsigned int r_type,
3248ed0d50c3Schristos const elfcpp::Sym<size, big_endian>&);
3249ed0d50c3Schristos
3250ed0d50c3Schristos inline bool
3251ed0d50c3Schristos global_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
3252ed0d50c3Schristos Target_aarch64<size, big_endian>* ,
3253ed0d50c3Schristos Sized_relobj_file<size, big_endian>* ,
3254ed0d50c3Schristos unsigned int ,
3255ed0d50c3Schristos Output_section* ,
3256ed0d50c3Schristos const elfcpp::Rela<size, big_endian>& ,
3257ed0d50c3Schristos unsigned int r_type,
3258ed0d50c3Schristos Symbol* gsym);
3259ed0d50c3Schristos
3260ed0d50c3Schristos private:
3261ed0d50c3Schristos static void
3262ed0d50c3Schristos unsupported_reloc_local(Sized_relobj_file<size, big_endian>*,
3263ed0d50c3Schristos unsigned int r_type);
3264ed0d50c3Schristos
3265ed0d50c3Schristos static void
3266ed0d50c3Schristos unsupported_reloc_global(Sized_relobj_file<size, big_endian>*,
3267ed0d50c3Schristos unsigned int r_type, Symbol*);
3268ed0d50c3Schristos
3269ed0d50c3Schristos inline bool
3270ed0d50c3Schristos possible_function_pointer_reloc(unsigned int r_type);
3271ed0d50c3Schristos
3272ed0d50c3Schristos void
3273ed0d50c3Schristos check_non_pic(Relobj*, unsigned int r_type);
3274ed0d50c3Schristos
3275ed0d50c3Schristos bool
3276ed0d50c3Schristos reloc_needs_plt_for_ifunc(Sized_relobj_file<size, big_endian>*,
3277ed0d50c3Schristos unsigned int r_type);
3278ed0d50c3Schristos
3279ed0d50c3Schristos // Whether we have issued an error about a non-PIC compilation.
3280ed0d50c3Schristos bool issued_non_pic_error_;
3281ed0d50c3Schristos };
3282ed0d50c3Schristos
3283ed0d50c3Schristos // The class which implements relocation.
3284ed0d50c3Schristos class Relocate
3285ed0d50c3Schristos {
3286ed0d50c3Schristos public:
Relocate()3287ed0d50c3Schristos Relocate()
3288ed0d50c3Schristos : skip_call_tls_get_addr_(false)
3289ed0d50c3Schristos { }
3290ed0d50c3Schristos
~Relocate()3291ed0d50c3Schristos ~Relocate()
3292ed0d50c3Schristos { }
3293ed0d50c3Schristos
3294ed0d50c3Schristos // Do a relocation. Return false if the caller should not issue
3295ed0d50c3Schristos // any warnings about this relocation.
3296ed0d50c3Schristos inline bool
3297ed0d50c3Schristos relocate(const Relocate_info<size, big_endian>*, unsigned int,
3298ed0d50c3Schristos Target_aarch64*, Output_section*, size_t, const unsigned char*,
3299ed0d50c3Schristos const Sized_symbol<size>*, const Symbol_value<size>*,
3300ed0d50c3Schristos unsigned char*, typename elfcpp::Elf_types<size>::Elf_Addr,
3301ed0d50c3Schristos section_size_type);
3302ed0d50c3Schristos
3303ed0d50c3Schristos private:
3304ed0d50c3Schristos inline typename AArch64_relocate_functions<size, big_endian>::Status
3305ed0d50c3Schristos relocate_tls(const Relocate_info<size, big_endian>*,
3306ed0d50c3Schristos Target_aarch64<size, big_endian>*,
3307ed0d50c3Schristos size_t,
3308ed0d50c3Schristos const elfcpp::Rela<size, big_endian>&,
3309ed0d50c3Schristos unsigned int r_type, const Sized_symbol<size>*,
3310ed0d50c3Schristos const Symbol_value<size>*,
3311ed0d50c3Schristos unsigned char*,
3312ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr);
3313ed0d50c3Schristos
3314ed0d50c3Schristos inline typename AArch64_relocate_functions<size, big_endian>::Status
3315ed0d50c3Schristos tls_gd_to_le(
3316ed0d50c3Schristos const Relocate_info<size, big_endian>*,
3317ed0d50c3Schristos Target_aarch64<size, big_endian>*,
3318ed0d50c3Schristos const elfcpp::Rela<size, big_endian>&,
3319ed0d50c3Schristos unsigned int,
3320ed0d50c3Schristos unsigned char*,
3321ed0d50c3Schristos const Symbol_value<size>*);
3322ed0d50c3Schristos
3323ed0d50c3Schristos inline typename AArch64_relocate_functions<size, big_endian>::Status
3324ed0d50c3Schristos tls_ld_to_le(
3325ed0d50c3Schristos const Relocate_info<size, big_endian>*,
3326ed0d50c3Schristos Target_aarch64<size, big_endian>*,
3327ed0d50c3Schristos const elfcpp::Rela<size, big_endian>&,
3328ed0d50c3Schristos unsigned int,
3329ed0d50c3Schristos unsigned char*,
3330ed0d50c3Schristos const Symbol_value<size>*);
3331ed0d50c3Schristos
3332ed0d50c3Schristos inline typename AArch64_relocate_functions<size, big_endian>::Status
3333ed0d50c3Schristos tls_ie_to_le(
3334ed0d50c3Schristos const Relocate_info<size, big_endian>*,
3335ed0d50c3Schristos Target_aarch64<size, big_endian>*,
3336ed0d50c3Schristos const elfcpp::Rela<size, big_endian>&,
3337ed0d50c3Schristos unsigned int,
3338ed0d50c3Schristos unsigned char*,
3339ed0d50c3Schristos const Symbol_value<size>*);
3340ed0d50c3Schristos
3341ed0d50c3Schristos inline typename AArch64_relocate_functions<size, big_endian>::Status
3342ed0d50c3Schristos tls_desc_gd_to_le(
3343ed0d50c3Schristos const Relocate_info<size, big_endian>*,
3344ed0d50c3Schristos Target_aarch64<size, big_endian>*,
3345ed0d50c3Schristos const elfcpp::Rela<size, big_endian>&,
3346ed0d50c3Schristos unsigned int,
3347ed0d50c3Schristos unsigned char*,
3348ed0d50c3Schristos const Symbol_value<size>*);
3349ed0d50c3Schristos
3350ed0d50c3Schristos inline typename AArch64_relocate_functions<size, big_endian>::Status
3351ed0d50c3Schristos tls_desc_gd_to_ie(
3352ed0d50c3Schristos const Relocate_info<size, big_endian>*,
3353ed0d50c3Schristos Target_aarch64<size, big_endian>*,
3354ed0d50c3Schristos const elfcpp::Rela<size, big_endian>&,
3355ed0d50c3Schristos unsigned int,
3356ed0d50c3Schristos unsigned char*,
3357ed0d50c3Schristos const Symbol_value<size>*,
3358ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr,
3359ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr);
3360ed0d50c3Schristos
3361ed0d50c3Schristos bool skip_call_tls_get_addr_;
3362ed0d50c3Schristos
3363ed0d50c3Schristos }; // End of class Relocate
3364ed0d50c3Schristos
3365ed0d50c3Schristos // Adjust TLS relocation type based on the options and whether this
3366ed0d50c3Schristos // is a local symbol.
3367ed0d50c3Schristos static tls::Tls_optimization
3368ed0d50c3Schristos optimize_tls_reloc(bool is_final, int r_type);
3369ed0d50c3Schristos
3370ed0d50c3Schristos // Get the GOT section, creating it if necessary.
3371ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>*
3372ed0d50c3Schristos got_section(Symbol_table*, Layout*);
3373ed0d50c3Schristos
3374ed0d50c3Schristos // Get the GOT PLT section.
3375ed0d50c3Schristos Output_data_space*
got_plt_section() const3376ed0d50c3Schristos got_plt_section() const
3377ed0d50c3Schristos {
3378ed0d50c3Schristos gold_assert(this->got_plt_ != NULL);
3379ed0d50c3Schristos return this->got_plt_;
3380ed0d50c3Schristos }
3381ed0d50c3Schristos
3382ed0d50c3Schristos // Get the GOT section for TLSDESC entries.
3383ed0d50c3Schristos Output_data_got<size, big_endian>*
got_tlsdesc_section() const3384ed0d50c3Schristos got_tlsdesc_section() const
3385ed0d50c3Schristos {
3386ed0d50c3Schristos gold_assert(this->got_tlsdesc_ != NULL);
3387ed0d50c3Schristos return this->got_tlsdesc_;
3388ed0d50c3Schristos }
3389ed0d50c3Schristos
3390ed0d50c3Schristos // Create the PLT section.
3391ed0d50c3Schristos void
3392ed0d50c3Schristos make_plt_section(Symbol_table* symtab, Layout* layout);
3393ed0d50c3Schristos
3394ed0d50c3Schristos // Create a PLT entry for a global symbol.
3395ed0d50c3Schristos void
3396ed0d50c3Schristos make_plt_entry(Symbol_table*, Layout*, Symbol*);
3397ed0d50c3Schristos
3398ed0d50c3Schristos // Create a PLT entry for a local STT_GNU_IFUNC symbol.
3399ed0d50c3Schristos void
3400ed0d50c3Schristos make_local_ifunc_plt_entry(Symbol_table*, Layout*,
3401ed0d50c3Schristos Sized_relobj_file<size, big_endian>* relobj,
3402ed0d50c3Schristos unsigned int local_sym_index);
3403ed0d50c3Schristos
3404ed0d50c3Schristos // Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
3405ed0d50c3Schristos void
3406ed0d50c3Schristos define_tls_base_symbol(Symbol_table*, Layout*);
3407ed0d50c3Schristos
3408ed0d50c3Schristos // Create the reserved PLT and GOT entries for the TLS descriptor resolver.
3409ed0d50c3Schristos void
3410ed0d50c3Schristos reserve_tlsdesc_entries(Symbol_table* symtab, Layout* layout);
3411ed0d50c3Schristos
3412ed0d50c3Schristos // Create a GOT entry for the TLS module index.
3413ed0d50c3Schristos unsigned int
3414ed0d50c3Schristos got_mod_index_entry(Symbol_table* symtab, Layout* layout,
3415ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object);
3416ed0d50c3Schristos
3417ed0d50c3Schristos // Get the PLT section.
3418ed0d50c3Schristos Output_data_plt_aarch64<size, big_endian>*
plt_section() const3419ed0d50c3Schristos plt_section() const
3420ed0d50c3Schristos {
3421ed0d50c3Schristos gold_assert(this->plt_ != NULL);
3422ed0d50c3Schristos return this->plt_;
3423ed0d50c3Schristos }
3424ed0d50c3Schristos
3425ed0d50c3Schristos // Helper method to create erratum stubs for ST_E_843419 and ST_E_835769. For
3426ed0d50c3Schristos // ST_E_843419, we need an additional field for adrp offset.
3427ed0d50c3Schristos void create_erratum_stub(
3428ed0d50c3Schristos AArch64_relobj<size, big_endian>* relobj,
3429ed0d50c3Schristos unsigned int shndx,
3430ed0d50c3Schristos section_size_type erratum_insn_offset,
3431ed0d50c3Schristos Address erratum_address,
3432ed0d50c3Schristos typename Insn_utilities::Insntype erratum_insn,
3433ed0d50c3Schristos int erratum_type,
3434ed0d50c3Schristos unsigned int e843419_adrp_offset=0);
3435ed0d50c3Schristos
3436ed0d50c3Schristos // Return whether this is a 3-insn erratum sequence.
3437ed0d50c3Schristos bool is_erratum_843419_sequence(
3438ed0d50c3Schristos typename elfcpp::Swap<32,big_endian>::Valtype insn1,
3439ed0d50c3Schristos typename elfcpp::Swap<32,big_endian>::Valtype insn2,
3440ed0d50c3Schristos typename elfcpp::Swap<32,big_endian>::Valtype insn3);
3441ed0d50c3Schristos
3442ed0d50c3Schristos // Return whether this is a 835769 sequence.
3443ed0d50c3Schristos // (Similarly implemented as in elfnn-aarch64.c.)
3444ed0d50c3Schristos bool is_erratum_835769_sequence(
3445ed0d50c3Schristos typename elfcpp::Swap<32,big_endian>::Valtype,
3446ed0d50c3Schristos typename elfcpp::Swap<32,big_endian>::Valtype);
3447ed0d50c3Schristos
3448ed0d50c3Schristos // Get the dynamic reloc section, creating it if necessary.
3449ed0d50c3Schristos Reloc_section*
3450ed0d50c3Schristos rela_dyn_section(Layout*);
3451ed0d50c3Schristos
3452ed0d50c3Schristos // Get the section to use for TLSDESC relocations.
3453ed0d50c3Schristos Reloc_section*
3454ed0d50c3Schristos rela_tlsdesc_section(Layout*) const;
3455ed0d50c3Schristos
3456ed0d50c3Schristos // Get the section to use for IRELATIVE relocations.
3457ed0d50c3Schristos Reloc_section*
3458ed0d50c3Schristos rela_irelative_section(Layout*);
3459ed0d50c3Schristos
3460ed0d50c3Schristos // Add a potential copy relocation.
3461ed0d50c3Schristos void
copy_reloc(Symbol_table * symtab,Layout * layout,Sized_relobj_file<size,big_endian> * object,unsigned int shndx,Output_section * output_section,Symbol * sym,const elfcpp::Rela<size,big_endian> & reloc)3462ed0d50c3Schristos copy_reloc(Symbol_table* symtab, Layout* layout,
3463ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object,
3464ed0d50c3Schristos unsigned int shndx, Output_section* output_section,
3465ed0d50c3Schristos Symbol* sym, const elfcpp::Rela<size, big_endian>& reloc)
3466ed0d50c3Schristos {
3467ed0d50c3Schristos unsigned int r_type = elfcpp::elf_r_type<size>(reloc.get_r_info());
3468ed0d50c3Schristos this->copy_relocs_.copy_reloc(symtab, layout,
3469ed0d50c3Schristos symtab->get_sized_symbol<size>(sym),
3470ed0d50c3Schristos object, shndx, output_section,
3471ed0d50c3Schristos r_type, reloc.get_r_offset(),
3472ed0d50c3Schristos reloc.get_r_addend(),
3473ed0d50c3Schristos this->rela_dyn_section(layout));
3474ed0d50c3Schristos }
3475ed0d50c3Schristos
3476ed0d50c3Schristos // Information about this specific target which we pass to the
3477ed0d50c3Schristos // general Target structure.
3478ed0d50c3Schristos static const Target::Target_info aarch64_info;
3479ed0d50c3Schristos
3480ed0d50c3Schristos // The types of GOT entries needed for this platform.
3481ed0d50c3Schristos // These values are exposed to the ABI in an incremental link.
3482ed0d50c3Schristos // Do not renumber existing values without changing the version
3483ed0d50c3Schristos // number of the .gnu_incremental_inputs section.
3484ed0d50c3Schristos enum Got_type
3485ed0d50c3Schristos {
3486ed0d50c3Schristos GOT_TYPE_STANDARD = 0, // GOT entry for a regular symbol
3487ed0d50c3Schristos GOT_TYPE_TLS_OFFSET = 1, // GOT entry for TLS offset
3488ed0d50c3Schristos GOT_TYPE_TLS_PAIR = 2, // GOT entry for TLS module/offset pair
3489ed0d50c3Schristos GOT_TYPE_TLS_DESC = 3 // GOT entry for TLS_DESC pair
3490ed0d50c3Schristos };
3491ed0d50c3Schristos
3492ed0d50c3Schristos // This type is used as the argument to the target specific
3493ed0d50c3Schristos // relocation routines. The only target specific reloc is
3494ed0d50c3Schristos // R_AARCh64_TLSDESC against a local symbol.
3495ed0d50c3Schristos struct Tlsdesc_info
3496ed0d50c3Schristos {
Tlsdesc_info__anond8ca3b600111::Target_aarch64::Tlsdesc_info3497ed0d50c3Schristos Tlsdesc_info(Sized_relobj_file<size, big_endian>* a_object,
3498ed0d50c3Schristos unsigned int a_r_sym)
3499ed0d50c3Schristos : object(a_object), r_sym(a_r_sym)
3500ed0d50c3Schristos { }
3501ed0d50c3Schristos
3502ed0d50c3Schristos // The object in which the local symbol is defined.
3503ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object;
3504ed0d50c3Schristos // The local symbol index in the object.
3505ed0d50c3Schristos unsigned int r_sym;
3506ed0d50c3Schristos };
3507ed0d50c3Schristos
3508ed0d50c3Schristos // The GOT section.
3509ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>* got_;
3510ed0d50c3Schristos // The PLT section.
3511ed0d50c3Schristos Output_data_plt_aarch64<size, big_endian>* plt_;
3512ed0d50c3Schristos // The GOT PLT section.
3513ed0d50c3Schristos Output_data_space* got_plt_;
3514ed0d50c3Schristos // The GOT section for IRELATIVE relocations.
3515ed0d50c3Schristos Output_data_space* got_irelative_;
3516ed0d50c3Schristos // The GOT section for TLSDESC relocations.
3517ed0d50c3Schristos Output_data_got<size, big_endian>* got_tlsdesc_;
3518ed0d50c3Schristos // The _GLOBAL_OFFSET_TABLE_ symbol.
3519ed0d50c3Schristos Symbol* global_offset_table_;
3520ed0d50c3Schristos // The dynamic reloc section.
3521ed0d50c3Schristos Reloc_section* rela_dyn_;
3522ed0d50c3Schristos // The section to use for IRELATIVE relocs.
3523ed0d50c3Schristos Reloc_section* rela_irelative_;
3524ed0d50c3Schristos // Relocs saved to avoid a COPY reloc.
3525ed0d50c3Schristos Copy_relocs<elfcpp::SHT_RELA, size, big_endian> copy_relocs_;
3526ed0d50c3Schristos // Offset of the GOT entry for the TLS module index.
3527ed0d50c3Schristos unsigned int got_mod_index_offset_;
3528ed0d50c3Schristos // We handle R_AARCH64_TLSDESC against a local symbol as a target
3529ed0d50c3Schristos // specific relocation. Here we store the object and local symbol
3530ed0d50c3Schristos // index for the relocation.
3531ed0d50c3Schristos std::vector<Tlsdesc_info> tlsdesc_reloc_info_;
3532ed0d50c3Schristos // True if the _TLS_MODULE_BASE_ symbol has been defined.
3533ed0d50c3Schristos bool tls_base_symbol_defined_;
3534ed0d50c3Schristos // List of stub_tables
3535ed0d50c3Schristos Stub_table_list stub_tables_;
3536ed0d50c3Schristos // Actual stub group size
3537ed0d50c3Schristos section_size_type stub_group_size_;
3538ed0d50c3Schristos AArch64_input_section_map aarch64_input_section_map_;
3539ed0d50c3Schristos }; // End of Target_aarch64
3540ed0d50c3Schristos
3541ed0d50c3Schristos
3542ed0d50c3Schristos template<>
3543ed0d50c3Schristos const Target::Target_info Target_aarch64<64, false>::aarch64_info =
3544ed0d50c3Schristos {
3545ed0d50c3Schristos 64, // size
3546ed0d50c3Schristos false, // is_big_endian
3547ed0d50c3Schristos elfcpp::EM_AARCH64, // machine_code
3548ed0d50c3Schristos false, // has_make_symbol
3549ed0d50c3Schristos false, // has_resolve
3550ed0d50c3Schristos false, // has_code_fill
355106324dcfSchristos false, // is_default_stack_executable
3552ed0d50c3Schristos true, // can_icf_inline_merge_sections
3553ed0d50c3Schristos '\0', // wrap_char
3554ed0d50c3Schristos "/lib/ld.so.1", // program interpreter
3555ed0d50c3Schristos 0x400000, // default_text_segment_address
3556ed0d50c3Schristos 0x10000, // abi_pagesize (overridable by -z max-page-size)
3557ed0d50c3Schristos 0x1000, // common_pagesize (overridable by -z common-page-size)
3558ed0d50c3Schristos false, // isolate_execinstr
3559ed0d50c3Schristos 0, // rosegment_gap
3560ed0d50c3Schristos elfcpp::SHN_UNDEF, // small_common_shndx
3561ed0d50c3Schristos elfcpp::SHN_UNDEF, // large_common_shndx
3562ed0d50c3Schristos 0, // small_common_section_flags
3563ed0d50c3Schristos 0, // large_common_section_flags
3564ed0d50c3Schristos NULL, // attributes_section
3565ed0d50c3Schristos NULL, // attributes_vendor
3566ed0d50c3Schristos "_start", // entry_symbol_name
3567ed0d50c3Schristos 32, // hash_entry_size
356806324dcfSchristos elfcpp::SHT_PROGBITS, // unwind_section_type
3569ed0d50c3Schristos };
3570ed0d50c3Schristos
3571ed0d50c3Schristos template<>
3572ed0d50c3Schristos const Target::Target_info Target_aarch64<32, false>::aarch64_info =
3573ed0d50c3Schristos {
3574ed0d50c3Schristos 32, // size
3575ed0d50c3Schristos false, // is_big_endian
3576ed0d50c3Schristos elfcpp::EM_AARCH64, // machine_code
3577ed0d50c3Schristos false, // has_make_symbol
3578ed0d50c3Schristos false, // has_resolve
3579ed0d50c3Schristos false, // has_code_fill
358006324dcfSchristos false, // is_default_stack_executable
3581ed0d50c3Schristos false, // can_icf_inline_merge_sections
3582ed0d50c3Schristos '\0', // wrap_char
3583ed0d50c3Schristos "/lib/ld.so.1", // program interpreter
3584ed0d50c3Schristos 0x400000, // default_text_segment_address
3585ed0d50c3Schristos 0x10000, // abi_pagesize (overridable by -z max-page-size)
3586ed0d50c3Schristos 0x1000, // common_pagesize (overridable by -z common-page-size)
3587ed0d50c3Schristos false, // isolate_execinstr
3588ed0d50c3Schristos 0, // rosegment_gap
3589ed0d50c3Schristos elfcpp::SHN_UNDEF, // small_common_shndx
3590ed0d50c3Schristos elfcpp::SHN_UNDEF, // large_common_shndx
3591ed0d50c3Schristos 0, // small_common_section_flags
3592ed0d50c3Schristos 0, // large_common_section_flags
3593ed0d50c3Schristos NULL, // attributes_section
3594ed0d50c3Schristos NULL, // attributes_vendor
3595ed0d50c3Schristos "_start", // entry_symbol_name
3596ed0d50c3Schristos 32, // hash_entry_size
359706324dcfSchristos elfcpp::SHT_PROGBITS, // unwind_section_type
3598ed0d50c3Schristos };
3599ed0d50c3Schristos
3600ed0d50c3Schristos template<>
3601ed0d50c3Schristos const Target::Target_info Target_aarch64<64, true>::aarch64_info =
3602ed0d50c3Schristos {
3603ed0d50c3Schristos 64, // size
3604ed0d50c3Schristos true, // is_big_endian
3605ed0d50c3Schristos elfcpp::EM_AARCH64, // machine_code
3606ed0d50c3Schristos false, // has_make_symbol
3607ed0d50c3Schristos false, // has_resolve
3608ed0d50c3Schristos false, // has_code_fill
360906324dcfSchristos false, // is_default_stack_executable
3610ed0d50c3Schristos true, // can_icf_inline_merge_sections
3611ed0d50c3Schristos '\0', // wrap_char
3612ed0d50c3Schristos "/lib/ld.so.1", // program interpreter
3613ed0d50c3Schristos 0x400000, // default_text_segment_address
3614ed0d50c3Schristos 0x10000, // abi_pagesize (overridable by -z max-page-size)
3615ed0d50c3Schristos 0x1000, // common_pagesize (overridable by -z common-page-size)
3616ed0d50c3Schristos false, // isolate_execinstr
3617ed0d50c3Schristos 0, // rosegment_gap
3618ed0d50c3Schristos elfcpp::SHN_UNDEF, // small_common_shndx
3619ed0d50c3Schristos elfcpp::SHN_UNDEF, // large_common_shndx
3620ed0d50c3Schristos 0, // small_common_section_flags
3621ed0d50c3Schristos 0, // large_common_section_flags
3622ed0d50c3Schristos NULL, // attributes_section
3623ed0d50c3Schristos NULL, // attributes_vendor
3624ed0d50c3Schristos "_start", // entry_symbol_name
3625ed0d50c3Schristos 32, // hash_entry_size
362606324dcfSchristos elfcpp::SHT_PROGBITS, // unwind_section_type
3627ed0d50c3Schristos };
3628ed0d50c3Schristos
3629ed0d50c3Schristos template<>
3630ed0d50c3Schristos const Target::Target_info Target_aarch64<32, true>::aarch64_info =
3631ed0d50c3Schristos {
3632ed0d50c3Schristos 32, // size
3633ed0d50c3Schristos true, // is_big_endian
3634ed0d50c3Schristos elfcpp::EM_AARCH64, // machine_code
3635ed0d50c3Schristos false, // has_make_symbol
3636ed0d50c3Schristos false, // has_resolve
3637ed0d50c3Schristos false, // has_code_fill
363806324dcfSchristos false, // is_default_stack_executable
3639ed0d50c3Schristos false, // can_icf_inline_merge_sections
3640ed0d50c3Schristos '\0', // wrap_char
3641ed0d50c3Schristos "/lib/ld.so.1", // program interpreter
3642ed0d50c3Schristos 0x400000, // default_text_segment_address
3643ed0d50c3Schristos 0x10000, // abi_pagesize (overridable by -z max-page-size)
3644ed0d50c3Schristos 0x1000, // common_pagesize (overridable by -z common-page-size)
3645ed0d50c3Schristos false, // isolate_execinstr
3646ed0d50c3Schristos 0, // rosegment_gap
3647ed0d50c3Schristos elfcpp::SHN_UNDEF, // small_common_shndx
3648ed0d50c3Schristos elfcpp::SHN_UNDEF, // large_common_shndx
3649ed0d50c3Schristos 0, // small_common_section_flags
3650ed0d50c3Schristos 0, // large_common_section_flags
3651ed0d50c3Schristos NULL, // attributes_section
3652ed0d50c3Schristos NULL, // attributes_vendor
3653ed0d50c3Schristos "_start", // entry_symbol_name
3654ed0d50c3Schristos 32, // hash_entry_size
365506324dcfSchristos elfcpp::SHT_PROGBITS, // unwind_section_type
3656ed0d50c3Schristos };
3657ed0d50c3Schristos
3658ed0d50c3Schristos // Get the GOT section, creating it if necessary.
3659ed0d50c3Schristos
3660ed0d50c3Schristos template<int size, bool big_endian>
3661ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>*
got_section(Symbol_table * symtab,Layout * layout)3662ed0d50c3Schristos Target_aarch64<size, big_endian>::got_section(Symbol_table* symtab,
3663ed0d50c3Schristos Layout* layout)
3664ed0d50c3Schristos {
3665ed0d50c3Schristos if (this->got_ == NULL)
3666ed0d50c3Schristos {
3667ed0d50c3Schristos gold_assert(symtab != NULL && layout != NULL);
3668ed0d50c3Schristos
3669ed0d50c3Schristos // When using -z now, we can treat .got.plt as a relro section.
3670ed0d50c3Schristos // Without -z now, it is modified after program startup by lazy
3671ed0d50c3Schristos // PLT relocations.
3672ed0d50c3Schristos bool is_got_plt_relro = parameters->options().now();
3673ed0d50c3Schristos Output_section_order got_order = (is_got_plt_relro
3674ed0d50c3Schristos ? ORDER_RELRO
3675ed0d50c3Schristos : ORDER_RELRO_LAST);
3676ed0d50c3Schristos Output_section_order got_plt_order = (is_got_plt_relro
3677ed0d50c3Schristos ? ORDER_RELRO
3678ed0d50c3Schristos : ORDER_NON_RELRO_FIRST);
3679ed0d50c3Schristos
3680ed0d50c3Schristos // Layout of .got and .got.plt sections.
3681ed0d50c3Schristos // .got[0] &_DYNAMIC <-_GLOBAL_OFFSET_TABLE_
3682ed0d50c3Schristos // ...
3683ed0d50c3Schristos // .gotplt[0] reserved for ld.so (&linkmap) <--DT_PLTGOT
3684ed0d50c3Schristos // .gotplt[1] reserved for ld.so (resolver)
3685ed0d50c3Schristos // .gotplt[2] reserved
3686ed0d50c3Schristos
3687ed0d50c3Schristos // Generate .got section.
3688ed0d50c3Schristos this->got_ = new Output_data_got_aarch64<size, big_endian>(symtab,
3689ed0d50c3Schristos layout);
3690ed0d50c3Schristos layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS,
3691ed0d50c3Schristos (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE),
3692ed0d50c3Schristos this->got_, got_order, true);
3693ed0d50c3Schristos // The first word of GOT is reserved for the address of .dynamic.
3694ed0d50c3Schristos // We put 0 here now. The value will be replaced later in
3695ed0d50c3Schristos // Output_data_got_aarch64::do_write.
3696ed0d50c3Schristos this->got_->add_constant(0);
3697ed0d50c3Schristos
3698ed0d50c3Schristos // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT.
3699ed0d50c3Schristos // _GLOBAL_OFFSET_TABLE_ value points to the start of the .got section,
3700ed0d50c3Schristos // even if there is a .got.plt section.
3701ed0d50c3Schristos this->global_offset_table_ =
3702ed0d50c3Schristos symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL,
3703ed0d50c3Schristos Symbol_table::PREDEFINED,
3704ed0d50c3Schristos this->got_,
3705ed0d50c3Schristos 0, 0, elfcpp::STT_OBJECT,
3706ed0d50c3Schristos elfcpp::STB_LOCAL,
3707ed0d50c3Schristos elfcpp::STV_HIDDEN, 0,
3708ed0d50c3Schristos false, false);
3709ed0d50c3Schristos
3710ed0d50c3Schristos // Generate .got.plt section.
3711ed0d50c3Schristos this->got_plt_ = new Output_data_space(size / 8, "** GOT PLT");
3712ed0d50c3Schristos layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
3713ed0d50c3Schristos (elfcpp::SHF_ALLOC
3714ed0d50c3Schristos | elfcpp::SHF_WRITE),
3715ed0d50c3Schristos this->got_plt_, got_plt_order,
3716ed0d50c3Schristos is_got_plt_relro);
3717ed0d50c3Schristos
3718ed0d50c3Schristos // The first three entries are reserved.
3719ed0d50c3Schristos this->got_plt_->set_current_data_size(
3720ed0d50c3Schristos AARCH64_GOTPLT_RESERVE_COUNT * (size / 8));
3721ed0d50c3Schristos
3722ed0d50c3Schristos // If there are any IRELATIVE relocations, they get GOT entries
3723ed0d50c3Schristos // in .got.plt after the jump slot entries.
3724ed0d50c3Schristos this->got_irelative_ = new Output_data_space(size / 8,
3725ed0d50c3Schristos "** GOT IRELATIVE PLT");
3726ed0d50c3Schristos layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
3727ed0d50c3Schristos (elfcpp::SHF_ALLOC
3728ed0d50c3Schristos | elfcpp::SHF_WRITE),
3729ed0d50c3Schristos this->got_irelative_,
3730ed0d50c3Schristos got_plt_order,
3731ed0d50c3Schristos is_got_plt_relro);
3732ed0d50c3Schristos
3733ed0d50c3Schristos // If there are any TLSDESC relocations, they get GOT entries in
3734ed0d50c3Schristos // .got.plt after the jump slot and IRELATIVE entries.
3735ed0d50c3Schristos this->got_tlsdesc_ = new Output_data_got<size, big_endian>();
3736ed0d50c3Schristos layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
3737ed0d50c3Schristos (elfcpp::SHF_ALLOC
3738ed0d50c3Schristos | elfcpp::SHF_WRITE),
3739ed0d50c3Schristos this->got_tlsdesc_,
3740ed0d50c3Schristos got_plt_order,
3741ed0d50c3Schristos is_got_plt_relro);
3742ed0d50c3Schristos
3743ed0d50c3Schristos if (!is_got_plt_relro)
3744ed0d50c3Schristos {
3745ed0d50c3Schristos // Those bytes can go into the relro segment.
3746ed0d50c3Schristos layout->increase_relro(
3747ed0d50c3Schristos AARCH64_GOTPLT_RESERVE_COUNT * (size / 8));
3748ed0d50c3Schristos }
3749ed0d50c3Schristos
3750ed0d50c3Schristos }
3751ed0d50c3Schristos return this->got_;
3752ed0d50c3Schristos }
3753ed0d50c3Schristos
3754ed0d50c3Schristos // Get the dynamic reloc section, creating it if necessary.
3755ed0d50c3Schristos
3756ed0d50c3Schristos template<int size, bool big_endian>
3757ed0d50c3Schristos typename Target_aarch64<size, big_endian>::Reloc_section*
rela_dyn_section(Layout * layout)3758ed0d50c3Schristos Target_aarch64<size, big_endian>::rela_dyn_section(Layout* layout)
3759ed0d50c3Schristos {
3760ed0d50c3Schristos if (this->rela_dyn_ == NULL)
3761ed0d50c3Schristos {
3762ed0d50c3Schristos gold_assert(layout != NULL);
3763ed0d50c3Schristos this->rela_dyn_ = new Reloc_section(parameters->options().combreloc());
3764ed0d50c3Schristos layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
3765ed0d50c3Schristos elfcpp::SHF_ALLOC, this->rela_dyn_,
3766ed0d50c3Schristos ORDER_DYNAMIC_RELOCS, false);
3767ed0d50c3Schristos }
3768ed0d50c3Schristos return this->rela_dyn_;
3769ed0d50c3Schristos }
3770ed0d50c3Schristos
3771ed0d50c3Schristos // Get the section to use for IRELATIVE relocs, creating it if
3772ed0d50c3Schristos // necessary. These go in .rela.dyn, but only after all other dynamic
3773ed0d50c3Schristos // relocations. They need to follow the other dynamic relocations so
3774ed0d50c3Schristos // that they can refer to global variables initialized by those
3775ed0d50c3Schristos // relocs.
3776ed0d50c3Schristos
3777ed0d50c3Schristos template<int size, bool big_endian>
3778ed0d50c3Schristos typename Target_aarch64<size, big_endian>::Reloc_section*
rela_irelative_section(Layout * layout)3779ed0d50c3Schristos Target_aarch64<size, big_endian>::rela_irelative_section(Layout* layout)
3780ed0d50c3Schristos {
3781ed0d50c3Schristos if (this->rela_irelative_ == NULL)
3782ed0d50c3Schristos {
3783ed0d50c3Schristos // Make sure we have already created the dynamic reloc section.
3784ed0d50c3Schristos this->rela_dyn_section(layout);
3785ed0d50c3Schristos this->rela_irelative_ = new Reloc_section(false);
3786ed0d50c3Schristos layout->add_output_section_data(".rela.dyn", elfcpp::SHT_RELA,
3787ed0d50c3Schristos elfcpp::SHF_ALLOC, this->rela_irelative_,
3788ed0d50c3Schristos ORDER_DYNAMIC_RELOCS, false);
3789ed0d50c3Schristos gold_assert(this->rela_dyn_->output_section()
3790ed0d50c3Schristos == this->rela_irelative_->output_section());
3791ed0d50c3Schristos }
3792ed0d50c3Schristos return this->rela_irelative_;
3793ed0d50c3Schristos }
3794ed0d50c3Schristos
3795ed0d50c3Schristos
3796ed0d50c3Schristos // do_make_elf_object to override the same function in the base class. We need
3797ed0d50c3Schristos // to use a target-specific sub-class of Sized_relobj_file<size, big_endian> to
3798ed0d50c3Schristos // store backend specific information. Hence we need to have our own ELF object
3799ed0d50c3Schristos // creation.
3800ed0d50c3Schristos
3801ed0d50c3Schristos template<int size, bool big_endian>
3802ed0d50c3Schristos Object*
do_make_elf_object(const std::string & name,Input_file * input_file,off_t offset,const elfcpp::Ehdr<size,big_endian> & ehdr)3803ed0d50c3Schristos Target_aarch64<size, big_endian>::do_make_elf_object(
3804ed0d50c3Schristos const std::string& name,
3805ed0d50c3Schristos Input_file* input_file,
3806ed0d50c3Schristos off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr)
3807ed0d50c3Schristos {
3808ed0d50c3Schristos int et = ehdr.get_e_type();
3809ed0d50c3Schristos // ET_EXEC files are valid input for --just-symbols/-R,
3810ed0d50c3Schristos // and we treat them as relocatable objects.
3811ed0d50c3Schristos if (et == elfcpp::ET_EXEC && input_file->just_symbols())
3812ed0d50c3Schristos return Sized_target<size, big_endian>::do_make_elf_object(
3813ed0d50c3Schristos name, input_file, offset, ehdr);
3814ed0d50c3Schristos else if (et == elfcpp::ET_REL)
3815ed0d50c3Schristos {
3816ed0d50c3Schristos AArch64_relobj<size, big_endian>* obj =
3817ed0d50c3Schristos new AArch64_relobj<size, big_endian>(name, input_file, offset, ehdr);
3818ed0d50c3Schristos obj->setup();
3819ed0d50c3Schristos return obj;
3820ed0d50c3Schristos }
3821ed0d50c3Schristos else if (et == elfcpp::ET_DYN)
3822ed0d50c3Schristos {
3823ed0d50c3Schristos // Keep base implementation.
3824ed0d50c3Schristos Sized_dynobj<size, big_endian>* obj =
3825ed0d50c3Schristos new Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr);
3826ed0d50c3Schristos obj->setup();
3827ed0d50c3Schristos return obj;
3828ed0d50c3Schristos }
3829ed0d50c3Schristos else
3830ed0d50c3Schristos {
3831ed0d50c3Schristos gold_error(_("%s: unsupported ELF file type %d"),
3832ed0d50c3Schristos name.c_str(), et);
3833ed0d50c3Schristos return NULL;
3834ed0d50c3Schristos }
3835ed0d50c3Schristos }
3836ed0d50c3Schristos
3837ed0d50c3Schristos
3838ed0d50c3Schristos // Scan a relocation for stub generation.
3839ed0d50c3Schristos
3840ed0d50c3Schristos template<int size, bool big_endian>
3841ed0d50c3Schristos void
scan_reloc_for_stub(const Relocate_info<size,big_endian> * relinfo,unsigned int r_type,const Sized_symbol<size> * gsym,unsigned int r_sym,const Symbol_value<size> * psymval,typename elfcpp::Elf_types<size>::Elf_Swxword addend,Address address)3842ed0d50c3Schristos Target_aarch64<size, big_endian>::scan_reloc_for_stub(
3843ed0d50c3Schristos const Relocate_info<size, big_endian>* relinfo,
3844ed0d50c3Schristos unsigned int r_type,
3845ed0d50c3Schristos const Sized_symbol<size>* gsym,
3846ed0d50c3Schristos unsigned int r_sym,
3847ed0d50c3Schristos const Symbol_value<size>* psymval,
3848ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Swxword addend,
3849ed0d50c3Schristos Address address)
3850ed0d50c3Schristos {
3851ed0d50c3Schristos const AArch64_relobj<size, big_endian>* aarch64_relobj =
3852ed0d50c3Schristos static_cast<AArch64_relobj<size, big_endian>*>(relinfo->object);
3853ed0d50c3Schristos
3854ed0d50c3Schristos Symbol_value<size> symval;
3855ed0d50c3Schristos if (gsym != NULL)
3856ed0d50c3Schristos {
3857ed0d50c3Schristos const AArch64_reloc_property* arp = aarch64_reloc_property_table->
3858ed0d50c3Schristos get_reloc_property(r_type);
3859ed0d50c3Schristos if (gsym->use_plt_offset(arp->reference_flags()))
3860ed0d50c3Schristos {
3861ed0d50c3Schristos // This uses a PLT, change the symbol value.
386206324dcfSchristos symval.set_output_value(this->plt_address_for_global(gsym));
3863ed0d50c3Schristos psymval = &symval;
3864ed0d50c3Schristos }
3865ed0d50c3Schristos else if (gsym->is_undefined())
386606324dcfSchristos {
386706324dcfSchristos // There is no need to generate a stub symbol if the original symbol
386806324dcfSchristos // is undefined.
386906324dcfSchristos gold_debug(DEBUG_TARGET,
387006324dcfSchristos "stub: not creating a stub for undefined symbol %s in file %s",
387106324dcfSchristos gsym->name(), aarch64_relobj->name().c_str());
3872ed0d50c3Schristos return;
3873ed0d50c3Schristos }
387406324dcfSchristos }
3875ed0d50c3Schristos
3876ed0d50c3Schristos // Get the symbol value.
3877ed0d50c3Schristos typename Symbol_value<size>::Value value = psymval->value(aarch64_relobj, 0);
3878ed0d50c3Schristos
3879ed0d50c3Schristos // Owing to pipelining, the PC relative branches below actually skip
3880ed0d50c3Schristos // two instructions when the branch offset is 0.
3881ed0d50c3Schristos Address destination = static_cast<Address>(-1);
3882ed0d50c3Schristos switch (r_type)
3883ed0d50c3Schristos {
3884ed0d50c3Schristos case elfcpp::R_AARCH64_CALL26:
3885ed0d50c3Schristos case elfcpp::R_AARCH64_JUMP26:
3886ed0d50c3Schristos destination = value + addend;
3887ed0d50c3Schristos break;
3888ed0d50c3Schristos default:
3889ed0d50c3Schristos gold_unreachable();
3890ed0d50c3Schristos }
3891ed0d50c3Schristos
3892ed0d50c3Schristos int stub_type = The_reloc_stub::
3893ed0d50c3Schristos stub_type_for_reloc(r_type, address, destination);
3894ed0d50c3Schristos if (stub_type == ST_NONE)
3895ed0d50c3Schristos return;
3896ed0d50c3Schristos
3897ed0d50c3Schristos The_stub_table* stub_table = aarch64_relobj->stub_table(relinfo->data_shndx);
3898ed0d50c3Schristos gold_assert(stub_table != NULL);
3899ed0d50c3Schristos
3900ed0d50c3Schristos The_reloc_stub_key key(stub_type, gsym, aarch64_relobj, r_sym, addend);
3901ed0d50c3Schristos The_reloc_stub* stub = stub_table->find_reloc_stub(key);
3902ed0d50c3Schristos if (stub == NULL)
3903ed0d50c3Schristos {
3904ed0d50c3Schristos stub = new The_reloc_stub(stub_type);
3905ed0d50c3Schristos stub_table->add_reloc_stub(stub, key);
3906ed0d50c3Schristos }
3907ed0d50c3Schristos stub->set_destination_address(destination);
3908ed0d50c3Schristos } // End of Target_aarch64::scan_reloc_for_stub
3909ed0d50c3Schristos
3910ed0d50c3Schristos
3911ed0d50c3Schristos // This function scans a relocation section for stub generation.
3912ed0d50c3Schristos // The template parameter Relocate must be a class type which provides
3913ed0d50c3Schristos // a single function, relocate(), which implements the machine
3914ed0d50c3Schristos // specific part of a relocation.
3915ed0d50c3Schristos
3916ed0d50c3Schristos // BIG_ENDIAN is the endianness of the data. SH_TYPE is the section type:
3917ed0d50c3Schristos // SHT_REL or SHT_RELA.
3918ed0d50c3Schristos
3919ed0d50c3Schristos // PRELOCS points to the relocation data. RELOC_COUNT is the number
3920ed0d50c3Schristos // of relocs. OUTPUT_SECTION is the output section.
3921ed0d50c3Schristos // NEEDS_SPECIAL_OFFSET_HANDLING is true if input offsets need to be
3922ed0d50c3Schristos // mapped to output offsets.
3923ed0d50c3Schristos
3924ed0d50c3Schristos // VIEW is the section data, VIEW_ADDRESS is its memory address, and
3925ed0d50c3Schristos // VIEW_SIZE is the size. These refer to the input section, unless
3926ed0d50c3Schristos // NEEDS_SPECIAL_OFFSET_HANDLING is true, in which case they refer to
3927ed0d50c3Schristos // the output section.
3928ed0d50c3Schristos
3929ed0d50c3Schristos template<int size, bool big_endian>
3930ed0d50c3Schristos template<int sh_type>
3931ed0d50c3Schristos void inline
scan_reloc_section_for_stubs(const Relocate_info<size,big_endian> * relinfo,const unsigned char * prelocs,size_t reloc_count,Output_section *,bool,const unsigned char *,Address view_address,section_size_type)3932ed0d50c3Schristos Target_aarch64<size, big_endian>::scan_reloc_section_for_stubs(
3933ed0d50c3Schristos const Relocate_info<size, big_endian>* relinfo,
3934ed0d50c3Schristos const unsigned char* prelocs,
3935ed0d50c3Schristos size_t reloc_count,
3936ed0d50c3Schristos Output_section* /*output_section*/,
3937ed0d50c3Schristos bool /*needs_special_offset_handling*/,
3938ed0d50c3Schristos const unsigned char* /*view*/,
3939ed0d50c3Schristos Address view_address,
3940ed0d50c3Schristos section_size_type)
3941ed0d50c3Schristos {
3942ed0d50c3Schristos typedef typename Reloc_types<sh_type,size,big_endian>::Reloc Reltype;
3943ed0d50c3Schristos
3944ed0d50c3Schristos const int reloc_size =
3945ed0d50c3Schristos Reloc_types<sh_type,size,big_endian>::reloc_size;
3946ed0d50c3Schristos AArch64_relobj<size, big_endian>* object =
3947ed0d50c3Schristos static_cast<AArch64_relobj<size, big_endian>*>(relinfo->object);
3948ed0d50c3Schristos unsigned int local_count = object->local_symbol_count();
3949ed0d50c3Schristos
3950ed0d50c3Schristos gold::Default_comdat_behavior default_comdat_behavior;
3951ed0d50c3Schristos Comdat_behavior comdat_behavior = CB_UNDETERMINED;
3952ed0d50c3Schristos
3953ed0d50c3Schristos for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
3954ed0d50c3Schristos {
3955ed0d50c3Schristos Reltype reloc(prelocs);
3956ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
3957ed0d50c3Schristos unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
3958ed0d50c3Schristos unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
3959ed0d50c3Schristos if (r_type != elfcpp::R_AARCH64_CALL26
3960ed0d50c3Schristos && r_type != elfcpp::R_AARCH64_JUMP26)
3961ed0d50c3Schristos continue;
3962ed0d50c3Schristos
3963ed0d50c3Schristos section_offset_type offset =
3964ed0d50c3Schristos convert_to_section_size_type(reloc.get_r_offset());
3965ed0d50c3Schristos
3966ed0d50c3Schristos // Get the addend.
3967ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Swxword addend =
3968ed0d50c3Schristos reloc.get_r_addend();
3969ed0d50c3Schristos
3970ed0d50c3Schristos const Sized_symbol<size>* sym;
3971ed0d50c3Schristos Symbol_value<size> symval;
3972ed0d50c3Schristos const Symbol_value<size> *psymval;
3973ed0d50c3Schristos bool is_defined_in_discarded_section;
3974ed0d50c3Schristos unsigned int shndx;
397506324dcfSchristos const Symbol* gsym = NULL;
3976ed0d50c3Schristos if (r_sym < local_count)
3977ed0d50c3Schristos {
3978ed0d50c3Schristos sym = NULL;
3979ed0d50c3Schristos psymval = object->local_symbol(r_sym);
3980ed0d50c3Schristos
3981ed0d50c3Schristos // If the local symbol belongs to a section we are discarding,
3982ed0d50c3Schristos // and that section is a debug section, try to find the
3983ed0d50c3Schristos // corresponding kept section and map this symbol to its
3984ed0d50c3Schristos // counterpart in the kept section. The symbol must not
3985ed0d50c3Schristos // correspond to a section we are folding.
3986ed0d50c3Schristos bool is_ordinary;
3987ed0d50c3Schristos shndx = psymval->input_shndx(&is_ordinary);
3988ed0d50c3Schristos is_defined_in_discarded_section =
3989ed0d50c3Schristos (is_ordinary
3990ed0d50c3Schristos && shndx != elfcpp::SHN_UNDEF
3991ed0d50c3Schristos && !object->is_section_included(shndx)
3992ed0d50c3Schristos && !relinfo->symtab->is_section_folded(object, shndx));
3993ed0d50c3Schristos
3994ed0d50c3Schristos // We need to compute the would-be final value of this local
3995ed0d50c3Schristos // symbol.
3996ed0d50c3Schristos if (!is_defined_in_discarded_section)
3997ed0d50c3Schristos {
3998ed0d50c3Schristos typedef Sized_relobj_file<size, big_endian> ObjType;
399906324dcfSchristos if (psymval->is_section_symbol())
400006324dcfSchristos symval.set_is_section_symbol();
4001ed0d50c3Schristos typename ObjType::Compute_final_local_value_status status =
4002ed0d50c3Schristos object->compute_final_local_value(r_sym, psymval, &symval,
4003ed0d50c3Schristos relinfo->symtab);
4004ed0d50c3Schristos if (status == ObjType::CFLV_OK)
4005ed0d50c3Schristos {
4006ed0d50c3Schristos // Currently we cannot handle a branch to a target in
4007ed0d50c3Schristos // a merged section. If this is the case, issue an error
4008ed0d50c3Schristos // and also free the merge symbol value.
4009ed0d50c3Schristos if (!symval.has_output_value())
4010ed0d50c3Schristos {
4011ed0d50c3Schristos const std::string& section_name =
4012ed0d50c3Schristos object->section_name(shndx);
4013ed0d50c3Schristos object->error(_("cannot handle branch to local %u "
4014ed0d50c3Schristos "in a merged section %s"),
4015ed0d50c3Schristos r_sym, section_name.c_str());
4016ed0d50c3Schristos }
4017ed0d50c3Schristos psymval = &symval;
4018ed0d50c3Schristos }
4019ed0d50c3Schristos else
4020ed0d50c3Schristos {
4021ed0d50c3Schristos // We cannot determine the final value.
4022ed0d50c3Schristos continue;
4023ed0d50c3Schristos }
4024ed0d50c3Schristos }
4025ed0d50c3Schristos }
4026ed0d50c3Schristos else
4027ed0d50c3Schristos {
4028ed0d50c3Schristos gsym = object->global_symbol(r_sym);
4029ed0d50c3Schristos gold_assert(gsym != NULL);
4030ed0d50c3Schristos if (gsym->is_forwarder())
4031ed0d50c3Schristos gsym = relinfo->symtab->resolve_forwards(gsym);
4032ed0d50c3Schristos
4033ed0d50c3Schristos sym = static_cast<const Sized_symbol<size>*>(gsym);
4034ed0d50c3Schristos if (sym->has_symtab_index() && sym->symtab_index() != -1U)
4035ed0d50c3Schristos symval.set_output_symtab_index(sym->symtab_index());
4036ed0d50c3Schristos else
4037ed0d50c3Schristos symval.set_no_output_symtab_entry();
4038ed0d50c3Schristos
4039ed0d50c3Schristos // We need to compute the would-be final value of this global
4040ed0d50c3Schristos // symbol.
4041ed0d50c3Schristos const Symbol_table* symtab = relinfo->symtab;
4042ed0d50c3Schristos const Sized_symbol<size>* sized_symbol =
4043ed0d50c3Schristos symtab->get_sized_symbol<size>(gsym);
4044ed0d50c3Schristos Symbol_table::Compute_final_value_status status;
4045ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr value =
4046ed0d50c3Schristos symtab->compute_final_value<size>(sized_symbol, &status);
4047ed0d50c3Schristos
4048ed0d50c3Schristos // Skip this if the symbol has not output section.
4049ed0d50c3Schristos if (status == Symbol_table::CFVS_NO_OUTPUT_SECTION)
4050ed0d50c3Schristos continue;
4051ed0d50c3Schristos symval.set_output_value(value);
4052ed0d50c3Schristos
4053ed0d50c3Schristos if (gsym->type() == elfcpp::STT_TLS)
4054ed0d50c3Schristos symval.set_is_tls_symbol();
4055ed0d50c3Schristos else if (gsym->type() == elfcpp::STT_GNU_IFUNC)
4056ed0d50c3Schristos symval.set_is_ifunc_symbol();
4057ed0d50c3Schristos psymval = &symval;
4058ed0d50c3Schristos
4059ed0d50c3Schristos is_defined_in_discarded_section =
4060ed0d50c3Schristos (gsym->is_defined_in_discarded_section()
4061ed0d50c3Schristos && gsym->is_undefined());
4062ed0d50c3Schristos shndx = 0;
4063ed0d50c3Schristos }
4064ed0d50c3Schristos
4065ed0d50c3Schristos Symbol_value<size> symval2;
4066ed0d50c3Schristos if (is_defined_in_discarded_section)
4067ed0d50c3Schristos {
4068ed0d50c3Schristos std::string name = object->section_name(relinfo->data_shndx);
406906324dcfSchristos
407006324dcfSchristos if (comdat_behavior == CB_UNDETERMINED)
4071ed0d50c3Schristos comdat_behavior = default_comdat_behavior.get(name.c_str());
407206324dcfSchristos
4073ed0d50c3Schristos if (comdat_behavior == CB_PRETEND)
4074ed0d50c3Schristos {
4075ed0d50c3Schristos bool found;
4076ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr value =
407706324dcfSchristos object->map_to_kept_section(shndx, name, &found);
4078ed0d50c3Schristos if (found)
4079ed0d50c3Schristos symval2.set_output_value(value + psymval->input_value());
4080ed0d50c3Schristos else
4081ed0d50c3Schristos symval2.set_output_value(0);
4082ed0d50c3Schristos }
4083ed0d50c3Schristos else
4084ed0d50c3Schristos {
408506324dcfSchristos if (comdat_behavior == CB_ERROR)
408606324dcfSchristos issue_discarded_error(relinfo, i, offset, r_sym, gsym);
4087ed0d50c3Schristos symval2.set_output_value(0);
4088ed0d50c3Schristos }
4089ed0d50c3Schristos symval2.set_no_output_symtab_entry();
4090ed0d50c3Schristos psymval = &symval2;
4091ed0d50c3Schristos }
4092ed0d50c3Schristos
4093ed0d50c3Schristos this->scan_reloc_for_stub(relinfo, r_type, sym, r_sym, psymval,
4094ed0d50c3Schristos addend, view_address + offset);
4095ed0d50c3Schristos } // End of iterating relocs in a section
4096ed0d50c3Schristos } // End of Target_aarch64::scan_reloc_section_for_stubs
4097ed0d50c3Schristos
4098ed0d50c3Schristos
4099ed0d50c3Schristos // Scan an input section for stub generation.
4100ed0d50c3Schristos
4101ed0d50c3Schristos template<int size, bool big_endian>
4102ed0d50c3Schristos void
scan_section_for_stubs(const Relocate_info<size,big_endian> * relinfo,unsigned int sh_type,const unsigned char * prelocs,size_t reloc_count,Output_section * output_section,bool needs_special_offset_handling,const unsigned char * view,Address view_address,section_size_type view_size)4103ed0d50c3Schristos Target_aarch64<size, big_endian>::scan_section_for_stubs(
4104ed0d50c3Schristos const Relocate_info<size, big_endian>* relinfo,
4105ed0d50c3Schristos unsigned int sh_type,
4106ed0d50c3Schristos const unsigned char* prelocs,
4107ed0d50c3Schristos size_t reloc_count,
4108ed0d50c3Schristos Output_section* output_section,
4109ed0d50c3Schristos bool needs_special_offset_handling,
4110ed0d50c3Schristos const unsigned char* view,
4111ed0d50c3Schristos Address view_address,
4112ed0d50c3Schristos section_size_type view_size)
4113ed0d50c3Schristos {
4114ed0d50c3Schristos gold_assert(sh_type == elfcpp::SHT_RELA);
4115ed0d50c3Schristos this->scan_reloc_section_for_stubs<elfcpp::SHT_RELA>(
4116ed0d50c3Schristos relinfo,
4117ed0d50c3Schristos prelocs,
4118ed0d50c3Schristos reloc_count,
4119ed0d50c3Schristos output_section,
4120ed0d50c3Schristos needs_special_offset_handling,
4121ed0d50c3Schristos view,
4122ed0d50c3Schristos view_address,
4123ed0d50c3Schristos view_size);
4124ed0d50c3Schristos }
4125ed0d50c3Schristos
4126ed0d50c3Schristos
412706324dcfSchristos // Relocate a single reloc stub.
4128ed0d50c3Schristos
4129ed0d50c3Schristos template<int size, bool big_endian>
4130ed0d50c3Schristos void Target_aarch64<size, big_endian>::
relocate_reloc_stub(The_reloc_stub * stub,const The_relocate_info *,Output_section *,unsigned char * view,Address address,section_size_type)413106324dcfSchristos relocate_reloc_stub(The_reloc_stub* stub,
4132ed0d50c3Schristos const The_relocate_info*,
4133ed0d50c3Schristos Output_section*,
4134ed0d50c3Schristos unsigned char* view,
4135ed0d50c3Schristos Address address,
4136ed0d50c3Schristos section_size_type)
4137ed0d50c3Schristos {
4138ed0d50c3Schristos typedef AArch64_relocate_functions<size, big_endian> The_reloc_functions;
4139ed0d50c3Schristos typedef typename The_reloc_functions::Status The_reloc_functions_status;
4140ed0d50c3Schristos typedef typename elfcpp::Swap<32,big_endian>::Valtype Insntype;
4141ed0d50c3Schristos
4142ed0d50c3Schristos Insntype* ip = reinterpret_cast<Insntype*>(view);
4143ed0d50c3Schristos int insn_number = stub->insn_num();
4144ed0d50c3Schristos const uint32_t* insns = stub->insns();
4145ed0d50c3Schristos // Check the insns are really those stub insns.
4146ed0d50c3Schristos for (int i = 0; i < insn_number; ++i)
4147ed0d50c3Schristos {
4148ed0d50c3Schristos Insntype insn = elfcpp::Swap<32,big_endian>::readval(ip + i);
4149ed0d50c3Schristos gold_assert(((uint32_t)insn == insns[i]));
4150ed0d50c3Schristos }
4151ed0d50c3Schristos
4152ed0d50c3Schristos Address dest = stub->destination_address();
4153ed0d50c3Schristos
4154ed0d50c3Schristos switch(stub->type())
4155ed0d50c3Schristos {
4156ed0d50c3Schristos case ST_ADRP_BRANCH:
4157ed0d50c3Schristos {
4158ed0d50c3Schristos // 1st reloc is ADR_PREL_PG_HI21
4159ed0d50c3Schristos The_reloc_functions_status status =
4160ed0d50c3Schristos The_reloc_functions::adrp(view, dest, address);
4161ed0d50c3Schristos // An error should never arise in the above step. If so, please
4162ed0d50c3Schristos // check 'aarch64_valid_for_adrp_p'.
4163ed0d50c3Schristos gold_assert(status == The_reloc_functions::STATUS_OKAY);
4164ed0d50c3Schristos
4165ed0d50c3Schristos // 2nd reloc is ADD_ABS_LO12_NC
4166ed0d50c3Schristos const AArch64_reloc_property* arp =
4167ed0d50c3Schristos aarch64_reloc_property_table->get_reloc_property(
4168ed0d50c3Schristos elfcpp::R_AARCH64_ADD_ABS_LO12_NC);
4169ed0d50c3Schristos gold_assert(arp != NULL);
4170ed0d50c3Schristos status = The_reloc_functions::template
4171ed0d50c3Schristos rela_general<32>(view + 4, dest, 0, arp);
4172ed0d50c3Schristos // An error should never arise, it is an "_NC" relocation.
4173ed0d50c3Schristos gold_assert(status == The_reloc_functions::STATUS_OKAY);
4174ed0d50c3Schristos }
4175ed0d50c3Schristos break;
4176ed0d50c3Schristos
4177ed0d50c3Schristos case ST_LONG_BRANCH_ABS:
4178ed0d50c3Schristos // 1st reloc is R_AARCH64_PREL64, at offset 8
4179ed0d50c3Schristos elfcpp::Swap<64,big_endian>::writeval(view + 8, dest);
4180ed0d50c3Schristos break;
4181ed0d50c3Schristos
4182ed0d50c3Schristos case ST_LONG_BRANCH_PCREL:
4183ed0d50c3Schristos {
4184ed0d50c3Schristos // "PC" calculation is the 2nd insn in the stub.
4185ed0d50c3Schristos uint64_t offset = dest - (address + 4);
4186ed0d50c3Schristos // Offset is placed at offset 4 and 5.
4187ed0d50c3Schristos elfcpp::Swap<64,big_endian>::writeval(view + 16, offset);
4188ed0d50c3Schristos }
4189ed0d50c3Schristos break;
4190ed0d50c3Schristos
4191ed0d50c3Schristos default:
4192ed0d50c3Schristos gold_unreachable();
4193ed0d50c3Schristos }
4194ed0d50c3Schristos }
4195ed0d50c3Schristos
4196ed0d50c3Schristos
4197ed0d50c3Schristos // A class to handle the PLT data.
4198ed0d50c3Schristos // This is an abstract base class that handles most of the linker details
4199ed0d50c3Schristos // but does not know the actual contents of PLT entries. The derived
4200ed0d50c3Schristos // classes below fill in those details.
4201ed0d50c3Schristos
4202ed0d50c3Schristos template<int size, bool big_endian>
4203ed0d50c3Schristos class Output_data_plt_aarch64 : public Output_section_data
4204ed0d50c3Schristos {
4205ed0d50c3Schristos public:
4206ed0d50c3Schristos typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>
4207ed0d50c3Schristos Reloc_section;
4208ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
4209ed0d50c3Schristos
Output_data_plt_aarch64(Layout * layout,uint64_t addralign,Output_data_got_aarch64<size,big_endian> * got,Output_data_space * got_plt,Output_data_space * got_irelative)4210ed0d50c3Schristos Output_data_plt_aarch64(Layout* layout,
4211ed0d50c3Schristos uint64_t addralign,
4212ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>* got,
4213ed0d50c3Schristos Output_data_space* got_plt,
4214ed0d50c3Schristos Output_data_space* got_irelative)
4215ed0d50c3Schristos : Output_section_data(addralign), tlsdesc_rel_(NULL), irelative_rel_(NULL),
4216ed0d50c3Schristos got_(got), got_plt_(got_plt), got_irelative_(got_irelative),
4217ed0d50c3Schristos count_(0), irelative_count_(0), tlsdesc_got_offset_(-1U)
4218ed0d50c3Schristos { this->init(layout); }
4219ed0d50c3Schristos
4220ed0d50c3Schristos // Initialize the PLT section.
4221ed0d50c3Schristos void
4222ed0d50c3Schristos init(Layout* layout);
4223ed0d50c3Schristos
4224ed0d50c3Schristos // Add an entry to the PLT.
4225ed0d50c3Schristos void
4226ed0d50c3Schristos add_entry(Symbol_table*, Layout*, Symbol* gsym);
4227ed0d50c3Schristos
4228ed0d50c3Schristos // Add an entry to the PLT for a local STT_GNU_IFUNC symbol.
4229ed0d50c3Schristos unsigned int
4230ed0d50c3Schristos add_local_ifunc_entry(Symbol_table* symtab, Layout*,
4231ed0d50c3Schristos Sized_relobj_file<size, big_endian>* relobj,
4232ed0d50c3Schristos unsigned int local_sym_index);
4233ed0d50c3Schristos
4234ed0d50c3Schristos // Add the relocation for a PLT entry.
4235ed0d50c3Schristos void
4236ed0d50c3Schristos add_relocation(Symbol_table*, Layout*, Symbol* gsym,
4237ed0d50c3Schristos unsigned int got_offset);
4238ed0d50c3Schristos
4239ed0d50c3Schristos // Add the reserved TLSDESC_PLT entry to the PLT.
4240ed0d50c3Schristos void
reserve_tlsdesc_entry(unsigned int got_offset)4241ed0d50c3Schristos reserve_tlsdesc_entry(unsigned int got_offset)
4242ed0d50c3Schristos { this->tlsdesc_got_offset_ = got_offset; }
4243ed0d50c3Schristos
4244ed0d50c3Schristos // Return true if a TLSDESC_PLT entry has been reserved.
4245ed0d50c3Schristos bool
has_tlsdesc_entry() const4246ed0d50c3Schristos has_tlsdesc_entry() const
4247ed0d50c3Schristos { return this->tlsdesc_got_offset_ != -1U; }
4248ed0d50c3Schristos
4249ed0d50c3Schristos // Return the GOT offset for the reserved TLSDESC_PLT entry.
4250ed0d50c3Schristos unsigned int
get_tlsdesc_got_offset() const4251ed0d50c3Schristos get_tlsdesc_got_offset() const
4252ed0d50c3Schristos { return this->tlsdesc_got_offset_; }
4253ed0d50c3Schristos
4254ed0d50c3Schristos // Return the PLT offset of the reserved TLSDESC_PLT entry.
4255ed0d50c3Schristos unsigned int
get_tlsdesc_plt_offset() const4256ed0d50c3Schristos get_tlsdesc_plt_offset() const
4257ed0d50c3Schristos {
4258ed0d50c3Schristos return (this->first_plt_entry_offset() +
4259ed0d50c3Schristos (this->count_ + this->irelative_count_)
4260ed0d50c3Schristos * this->get_plt_entry_size());
4261ed0d50c3Schristos }
4262ed0d50c3Schristos
4263ed0d50c3Schristos // Return the .rela.plt section data.
4264ed0d50c3Schristos Reloc_section*
rela_plt()4265ed0d50c3Schristos rela_plt()
4266ed0d50c3Schristos { return this->rel_; }
4267ed0d50c3Schristos
4268ed0d50c3Schristos // Return where the TLSDESC relocations should go.
4269ed0d50c3Schristos Reloc_section*
4270ed0d50c3Schristos rela_tlsdesc(Layout*);
4271ed0d50c3Schristos
4272ed0d50c3Schristos // Return where the IRELATIVE relocations should go in the PLT
4273ed0d50c3Schristos // relocations.
4274ed0d50c3Schristos Reloc_section*
4275ed0d50c3Schristos rela_irelative(Symbol_table*, Layout*);
4276ed0d50c3Schristos
4277ed0d50c3Schristos // Return whether we created a section for IRELATIVE relocations.
4278ed0d50c3Schristos bool
has_irelative_section() const4279ed0d50c3Schristos has_irelative_section() const
4280ed0d50c3Schristos { return this->irelative_rel_ != NULL; }
4281ed0d50c3Schristos
4282ed0d50c3Schristos // Return the number of PLT entries.
4283ed0d50c3Schristos unsigned int
entry_count() const4284ed0d50c3Schristos entry_count() const
4285ed0d50c3Schristos { return this->count_ + this->irelative_count_; }
4286ed0d50c3Schristos
4287ed0d50c3Schristos // Return the offset of the first non-reserved PLT entry.
4288ed0d50c3Schristos unsigned int
first_plt_entry_offset() const4289ed0d50c3Schristos first_plt_entry_offset() const
4290ed0d50c3Schristos { return this->do_first_plt_entry_offset(); }
4291ed0d50c3Schristos
4292ed0d50c3Schristos // Return the size of a PLT entry.
4293ed0d50c3Schristos unsigned int
get_plt_entry_size() const4294ed0d50c3Schristos get_plt_entry_size() const
4295ed0d50c3Schristos { return this->do_get_plt_entry_size(); }
4296ed0d50c3Schristos
4297ed0d50c3Schristos // Return the reserved tlsdesc entry size.
4298ed0d50c3Schristos unsigned int
get_plt_tlsdesc_entry_size() const4299ed0d50c3Schristos get_plt_tlsdesc_entry_size() const
4300ed0d50c3Schristos { return this->do_get_plt_tlsdesc_entry_size(); }
4301ed0d50c3Schristos
4302ed0d50c3Schristos // Return the PLT address to use for a global symbol.
4303ed0d50c3Schristos uint64_t
4304ed0d50c3Schristos address_for_global(const Symbol*);
4305ed0d50c3Schristos
4306ed0d50c3Schristos // Return the PLT address to use for a local symbol.
4307ed0d50c3Schristos uint64_t
4308ed0d50c3Schristos address_for_local(const Relobj*, unsigned int symndx);
4309ed0d50c3Schristos
4310ed0d50c3Schristos protected:
4311ed0d50c3Schristos // Fill in the first PLT entry.
4312ed0d50c3Schristos void
fill_first_plt_entry(unsigned char * pov,Address got_address,Address plt_address)4313ed0d50c3Schristos fill_first_plt_entry(unsigned char* pov,
4314ed0d50c3Schristos Address got_address,
4315ed0d50c3Schristos Address plt_address)
4316ed0d50c3Schristos { this->do_fill_first_plt_entry(pov, got_address, plt_address); }
4317ed0d50c3Schristos
4318ed0d50c3Schristos // Fill in a normal PLT entry.
4319ed0d50c3Schristos void
fill_plt_entry(unsigned char * pov,Address got_address,Address plt_address,unsigned int got_offset,unsigned int plt_offset)4320ed0d50c3Schristos fill_plt_entry(unsigned char* pov,
4321ed0d50c3Schristos Address got_address,
4322ed0d50c3Schristos Address plt_address,
4323ed0d50c3Schristos unsigned int got_offset,
4324ed0d50c3Schristos unsigned int plt_offset)
4325ed0d50c3Schristos {
4326ed0d50c3Schristos this->do_fill_plt_entry(pov, got_address, plt_address,
4327ed0d50c3Schristos got_offset, plt_offset);
4328ed0d50c3Schristos }
4329ed0d50c3Schristos
4330ed0d50c3Schristos // Fill in the reserved TLSDESC PLT entry.
4331ed0d50c3Schristos void
fill_tlsdesc_entry(unsigned char * pov,Address gotplt_address,Address plt_address,Address got_base,unsigned int tlsdesc_got_offset,unsigned int plt_offset)4332ed0d50c3Schristos fill_tlsdesc_entry(unsigned char* pov,
4333ed0d50c3Schristos Address gotplt_address,
4334ed0d50c3Schristos Address plt_address,
4335ed0d50c3Schristos Address got_base,
4336ed0d50c3Schristos unsigned int tlsdesc_got_offset,
4337ed0d50c3Schristos unsigned int plt_offset)
4338ed0d50c3Schristos {
4339ed0d50c3Schristos this->do_fill_tlsdesc_entry(pov, gotplt_address, plt_address, got_base,
4340ed0d50c3Schristos tlsdesc_got_offset, plt_offset);
4341ed0d50c3Schristos }
4342ed0d50c3Schristos
4343ed0d50c3Schristos virtual unsigned int
4344ed0d50c3Schristos do_first_plt_entry_offset() const = 0;
4345ed0d50c3Schristos
4346ed0d50c3Schristos virtual unsigned int
4347ed0d50c3Schristos do_get_plt_entry_size() const = 0;
4348ed0d50c3Schristos
4349ed0d50c3Schristos virtual unsigned int
4350ed0d50c3Schristos do_get_plt_tlsdesc_entry_size() const = 0;
4351ed0d50c3Schristos
4352ed0d50c3Schristos virtual void
4353ed0d50c3Schristos do_fill_first_plt_entry(unsigned char* pov,
4354ed0d50c3Schristos Address got_addr,
4355ed0d50c3Schristos Address plt_addr) = 0;
4356ed0d50c3Schristos
4357ed0d50c3Schristos virtual void
4358ed0d50c3Schristos do_fill_plt_entry(unsigned char* pov,
4359ed0d50c3Schristos Address got_address,
4360ed0d50c3Schristos Address plt_address,
4361ed0d50c3Schristos unsigned int got_offset,
4362ed0d50c3Schristos unsigned int plt_offset) = 0;
4363ed0d50c3Schristos
4364ed0d50c3Schristos virtual void
4365ed0d50c3Schristos do_fill_tlsdesc_entry(unsigned char* pov,
4366ed0d50c3Schristos Address gotplt_address,
4367ed0d50c3Schristos Address plt_address,
4368ed0d50c3Schristos Address got_base,
4369ed0d50c3Schristos unsigned int tlsdesc_got_offset,
4370ed0d50c3Schristos unsigned int plt_offset) = 0;
4371ed0d50c3Schristos
4372ed0d50c3Schristos void
4373ed0d50c3Schristos do_adjust_output_section(Output_section* os);
4374ed0d50c3Schristos
4375ed0d50c3Schristos // Write to a map file.
4376ed0d50c3Schristos void
do_print_to_mapfile(Mapfile * mapfile) const4377ed0d50c3Schristos do_print_to_mapfile(Mapfile* mapfile) const
4378ed0d50c3Schristos { mapfile->print_output_data(this, _("** PLT")); }
4379ed0d50c3Schristos
4380ed0d50c3Schristos private:
4381ed0d50c3Schristos // Set the final size.
4382ed0d50c3Schristos void
4383ed0d50c3Schristos set_final_data_size();
4384ed0d50c3Schristos
4385ed0d50c3Schristos // Write out the PLT data.
4386ed0d50c3Schristos void
4387ed0d50c3Schristos do_write(Output_file*);
4388ed0d50c3Schristos
4389ed0d50c3Schristos // The reloc section.
4390ed0d50c3Schristos Reloc_section* rel_;
4391ed0d50c3Schristos
4392ed0d50c3Schristos // The TLSDESC relocs, if necessary. These must follow the regular
4393ed0d50c3Schristos // PLT relocs.
4394ed0d50c3Schristos Reloc_section* tlsdesc_rel_;
4395ed0d50c3Schristos
4396ed0d50c3Schristos // The IRELATIVE relocs, if necessary. These must follow the
4397ed0d50c3Schristos // regular PLT relocations.
4398ed0d50c3Schristos Reloc_section* irelative_rel_;
4399ed0d50c3Schristos
4400ed0d50c3Schristos // The .got section.
4401ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>* got_;
4402ed0d50c3Schristos
4403ed0d50c3Schristos // The .got.plt section.
4404ed0d50c3Schristos Output_data_space* got_plt_;
4405ed0d50c3Schristos
4406ed0d50c3Schristos // The part of the .got.plt section used for IRELATIVE relocs.
4407ed0d50c3Schristos Output_data_space* got_irelative_;
4408ed0d50c3Schristos
4409ed0d50c3Schristos // The number of PLT entries.
4410ed0d50c3Schristos unsigned int count_;
4411ed0d50c3Schristos
4412ed0d50c3Schristos // Number of PLT entries with R_AARCH64_IRELATIVE relocs. These
4413ed0d50c3Schristos // follow the regular PLT entries.
4414ed0d50c3Schristos unsigned int irelative_count_;
4415ed0d50c3Schristos
4416ed0d50c3Schristos // GOT offset of the reserved TLSDESC_GOT entry for the lazy trampoline.
4417ed0d50c3Schristos // Communicated to the loader via DT_TLSDESC_GOT. The magic value -1
4418ed0d50c3Schristos // indicates an offset is not allocated.
4419ed0d50c3Schristos unsigned int tlsdesc_got_offset_;
4420ed0d50c3Schristos };
4421ed0d50c3Schristos
4422ed0d50c3Schristos // Initialize the PLT section.
4423ed0d50c3Schristos
4424ed0d50c3Schristos template<int size, bool big_endian>
4425ed0d50c3Schristos void
init(Layout * layout)4426ed0d50c3Schristos Output_data_plt_aarch64<size, big_endian>::init(Layout* layout)
4427ed0d50c3Schristos {
4428ed0d50c3Schristos this->rel_ = new Reloc_section(false);
4429ed0d50c3Schristos layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
4430ed0d50c3Schristos elfcpp::SHF_ALLOC, this->rel_,
4431ed0d50c3Schristos ORDER_DYNAMIC_PLT_RELOCS, false);
4432ed0d50c3Schristos }
4433ed0d50c3Schristos
4434ed0d50c3Schristos template<int size, bool big_endian>
4435ed0d50c3Schristos void
do_adjust_output_section(Output_section * os)4436ed0d50c3Schristos Output_data_plt_aarch64<size, big_endian>::do_adjust_output_section(
4437ed0d50c3Schristos Output_section* os)
4438ed0d50c3Schristos {
4439ed0d50c3Schristos os->set_entsize(this->get_plt_entry_size());
4440ed0d50c3Schristos }
4441ed0d50c3Schristos
4442ed0d50c3Schristos // Add an entry to the PLT.
4443ed0d50c3Schristos
4444ed0d50c3Schristos template<int size, bool big_endian>
4445ed0d50c3Schristos void
add_entry(Symbol_table * symtab,Layout * layout,Symbol * gsym)4446ed0d50c3Schristos Output_data_plt_aarch64<size, big_endian>::add_entry(Symbol_table* symtab,
4447ed0d50c3Schristos Layout* layout, Symbol* gsym)
4448ed0d50c3Schristos {
4449ed0d50c3Schristos gold_assert(!gsym->has_plt_offset());
4450ed0d50c3Schristos
4451ed0d50c3Schristos unsigned int* pcount;
4452ed0d50c3Schristos unsigned int plt_reserved;
4453ed0d50c3Schristos Output_section_data_build* got;
4454ed0d50c3Schristos
4455ed0d50c3Schristos if (gsym->type() == elfcpp::STT_GNU_IFUNC
4456ed0d50c3Schristos && gsym->can_use_relative_reloc(false))
4457ed0d50c3Schristos {
4458ed0d50c3Schristos pcount = &this->irelative_count_;
4459ed0d50c3Schristos plt_reserved = 0;
4460ed0d50c3Schristos got = this->got_irelative_;
4461ed0d50c3Schristos }
4462ed0d50c3Schristos else
4463ed0d50c3Schristos {
4464ed0d50c3Schristos pcount = &this->count_;
4465ed0d50c3Schristos plt_reserved = this->first_plt_entry_offset();
4466ed0d50c3Schristos got = this->got_plt_;
4467ed0d50c3Schristos }
4468ed0d50c3Schristos
4469ed0d50c3Schristos gsym->set_plt_offset((*pcount) * this->get_plt_entry_size()
4470ed0d50c3Schristos + plt_reserved);
4471ed0d50c3Schristos
4472ed0d50c3Schristos ++*pcount;
4473ed0d50c3Schristos
4474ed0d50c3Schristos section_offset_type got_offset = got->current_data_size();
4475ed0d50c3Schristos
4476ed0d50c3Schristos // Every PLT entry needs a GOT entry which points back to the PLT
4477ed0d50c3Schristos // entry (this will be changed by the dynamic linker, normally
4478ed0d50c3Schristos // lazily when the function is called).
4479ed0d50c3Schristos got->set_current_data_size(got_offset + size / 8);
4480ed0d50c3Schristos
4481ed0d50c3Schristos // Every PLT entry needs a reloc.
4482ed0d50c3Schristos this->add_relocation(symtab, layout, gsym, got_offset);
4483ed0d50c3Schristos
4484ed0d50c3Schristos // Note that we don't need to save the symbol. The contents of the
4485ed0d50c3Schristos // PLT are independent of which symbols are used. The symbols only
4486ed0d50c3Schristos // appear in the relocations.
4487ed0d50c3Schristos }
4488ed0d50c3Schristos
4489ed0d50c3Schristos // Add an entry to the PLT for a local STT_GNU_IFUNC symbol. Return
4490ed0d50c3Schristos // the PLT offset.
4491ed0d50c3Schristos
4492ed0d50c3Schristos template<int size, bool big_endian>
4493ed0d50c3Schristos unsigned int
add_local_ifunc_entry(Symbol_table * symtab,Layout * layout,Sized_relobj_file<size,big_endian> * relobj,unsigned int local_sym_index)4494ed0d50c3Schristos Output_data_plt_aarch64<size, big_endian>::add_local_ifunc_entry(
4495ed0d50c3Schristos Symbol_table* symtab,
4496ed0d50c3Schristos Layout* layout,
4497ed0d50c3Schristos Sized_relobj_file<size, big_endian>* relobj,
4498ed0d50c3Schristos unsigned int local_sym_index)
4499ed0d50c3Schristos {
4500ed0d50c3Schristos unsigned int plt_offset = this->irelative_count_ * this->get_plt_entry_size();
4501ed0d50c3Schristos ++this->irelative_count_;
4502ed0d50c3Schristos
4503ed0d50c3Schristos section_offset_type got_offset = this->got_irelative_->current_data_size();
4504ed0d50c3Schristos
4505ed0d50c3Schristos // Every PLT entry needs a GOT entry which points back to the PLT
4506ed0d50c3Schristos // entry.
4507ed0d50c3Schristos this->got_irelative_->set_current_data_size(got_offset + size / 8);
4508ed0d50c3Schristos
4509ed0d50c3Schristos // Every PLT entry needs a reloc.
4510ed0d50c3Schristos Reloc_section* rela = this->rela_irelative(symtab, layout);
4511ed0d50c3Schristos rela->add_symbolless_local_addend(relobj, local_sym_index,
4512ed0d50c3Schristos elfcpp::R_AARCH64_IRELATIVE,
4513ed0d50c3Schristos this->got_irelative_, got_offset, 0);
4514ed0d50c3Schristos
4515ed0d50c3Schristos return plt_offset;
4516ed0d50c3Schristos }
4517ed0d50c3Schristos
4518ed0d50c3Schristos // Add the relocation for a PLT entry.
4519ed0d50c3Schristos
4520ed0d50c3Schristos template<int size, bool big_endian>
4521ed0d50c3Schristos void
add_relocation(Symbol_table * symtab,Layout * layout,Symbol * gsym,unsigned int got_offset)4522ed0d50c3Schristos Output_data_plt_aarch64<size, big_endian>::add_relocation(
4523ed0d50c3Schristos Symbol_table* symtab, Layout* layout, Symbol* gsym, unsigned int got_offset)
4524ed0d50c3Schristos {
4525ed0d50c3Schristos if (gsym->type() == elfcpp::STT_GNU_IFUNC
4526ed0d50c3Schristos && gsym->can_use_relative_reloc(false))
4527ed0d50c3Schristos {
4528ed0d50c3Schristos Reloc_section* rela = this->rela_irelative(symtab, layout);
4529ed0d50c3Schristos rela->add_symbolless_global_addend(gsym, elfcpp::R_AARCH64_IRELATIVE,
4530ed0d50c3Schristos this->got_irelative_, got_offset, 0);
4531ed0d50c3Schristos }
4532ed0d50c3Schristos else
4533ed0d50c3Schristos {
4534ed0d50c3Schristos gsym->set_needs_dynsym_entry();
4535ed0d50c3Schristos this->rel_->add_global(gsym, elfcpp::R_AARCH64_JUMP_SLOT, this->got_plt_,
4536ed0d50c3Schristos got_offset, 0);
4537ed0d50c3Schristos }
4538ed0d50c3Schristos }
4539ed0d50c3Schristos
4540ed0d50c3Schristos // Return where the TLSDESC relocations should go, creating it if
4541ed0d50c3Schristos // necessary. These follow the JUMP_SLOT relocations.
4542ed0d50c3Schristos
4543ed0d50c3Schristos template<int size, bool big_endian>
4544ed0d50c3Schristos typename Output_data_plt_aarch64<size, big_endian>::Reloc_section*
rela_tlsdesc(Layout * layout)4545ed0d50c3Schristos Output_data_plt_aarch64<size, big_endian>::rela_tlsdesc(Layout* layout)
4546ed0d50c3Schristos {
4547ed0d50c3Schristos if (this->tlsdesc_rel_ == NULL)
4548ed0d50c3Schristos {
4549ed0d50c3Schristos this->tlsdesc_rel_ = new Reloc_section(false);
4550ed0d50c3Schristos layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
4551ed0d50c3Schristos elfcpp::SHF_ALLOC, this->tlsdesc_rel_,
4552ed0d50c3Schristos ORDER_DYNAMIC_PLT_RELOCS, false);
4553ed0d50c3Schristos gold_assert(this->tlsdesc_rel_->output_section()
4554ed0d50c3Schristos == this->rel_->output_section());
4555ed0d50c3Schristos }
4556ed0d50c3Schristos return this->tlsdesc_rel_;
4557ed0d50c3Schristos }
4558ed0d50c3Schristos
4559ed0d50c3Schristos // Return where the IRELATIVE relocations should go in the PLT. These
4560ed0d50c3Schristos // follow the JUMP_SLOT and the TLSDESC relocations.
4561ed0d50c3Schristos
4562ed0d50c3Schristos template<int size, bool big_endian>
4563ed0d50c3Schristos typename Output_data_plt_aarch64<size, big_endian>::Reloc_section*
rela_irelative(Symbol_table * symtab,Layout * layout)4564ed0d50c3Schristos Output_data_plt_aarch64<size, big_endian>::rela_irelative(Symbol_table* symtab,
4565ed0d50c3Schristos Layout* layout)
4566ed0d50c3Schristos {
4567ed0d50c3Schristos if (this->irelative_rel_ == NULL)
4568ed0d50c3Schristos {
4569ed0d50c3Schristos // Make sure we have a place for the TLSDESC relocations, in
4570ed0d50c3Schristos // case we see any later on.
4571ed0d50c3Schristos this->rela_tlsdesc(layout);
4572ed0d50c3Schristos this->irelative_rel_ = new Reloc_section(false);
4573ed0d50c3Schristos layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
4574ed0d50c3Schristos elfcpp::SHF_ALLOC, this->irelative_rel_,
4575ed0d50c3Schristos ORDER_DYNAMIC_PLT_RELOCS, false);
4576ed0d50c3Schristos gold_assert(this->irelative_rel_->output_section()
4577ed0d50c3Schristos == this->rel_->output_section());
4578ed0d50c3Schristos
4579ed0d50c3Schristos if (parameters->doing_static_link())
4580ed0d50c3Schristos {
4581ed0d50c3Schristos // A statically linked executable will only have a .rela.plt
4582ed0d50c3Schristos // section to hold R_AARCH64_IRELATIVE relocs for
4583ed0d50c3Schristos // STT_GNU_IFUNC symbols. The library will use these
4584ed0d50c3Schristos // symbols to locate the IRELATIVE relocs at program startup
4585ed0d50c3Schristos // time.
4586ed0d50c3Schristos symtab->define_in_output_data("__rela_iplt_start", NULL,
4587ed0d50c3Schristos Symbol_table::PREDEFINED,
4588ed0d50c3Schristos this->irelative_rel_, 0, 0,
4589ed0d50c3Schristos elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
4590ed0d50c3Schristos elfcpp::STV_HIDDEN, 0, false, true);
4591ed0d50c3Schristos symtab->define_in_output_data("__rela_iplt_end", NULL,
4592ed0d50c3Schristos Symbol_table::PREDEFINED,
4593ed0d50c3Schristos this->irelative_rel_, 0, 0,
4594ed0d50c3Schristos elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL,
4595ed0d50c3Schristos elfcpp::STV_HIDDEN, 0, true, true);
4596ed0d50c3Schristos }
4597ed0d50c3Schristos }
4598ed0d50c3Schristos return this->irelative_rel_;
4599ed0d50c3Schristos }
4600ed0d50c3Schristos
4601ed0d50c3Schristos // Return the PLT address to use for a global symbol.
4602ed0d50c3Schristos
4603ed0d50c3Schristos template<int size, bool big_endian>
4604ed0d50c3Schristos uint64_t
address_for_global(const Symbol * gsym)4605ed0d50c3Schristos Output_data_plt_aarch64<size, big_endian>::address_for_global(
4606ed0d50c3Schristos const Symbol* gsym)
4607ed0d50c3Schristos {
4608ed0d50c3Schristos uint64_t offset = 0;
4609ed0d50c3Schristos if (gsym->type() == elfcpp::STT_GNU_IFUNC
4610ed0d50c3Schristos && gsym->can_use_relative_reloc(false))
4611ed0d50c3Schristos offset = (this->first_plt_entry_offset() +
4612ed0d50c3Schristos this->count_ * this->get_plt_entry_size());
4613ed0d50c3Schristos return this->address() + offset + gsym->plt_offset();
4614ed0d50c3Schristos }
4615ed0d50c3Schristos
4616ed0d50c3Schristos // Return the PLT address to use for a local symbol. These are always
4617ed0d50c3Schristos // IRELATIVE relocs.
4618ed0d50c3Schristos
4619ed0d50c3Schristos template<int size, bool big_endian>
4620ed0d50c3Schristos uint64_t
address_for_local(const Relobj * object,unsigned int r_sym)4621ed0d50c3Schristos Output_data_plt_aarch64<size, big_endian>::address_for_local(
4622ed0d50c3Schristos const Relobj* object,
4623ed0d50c3Schristos unsigned int r_sym)
4624ed0d50c3Schristos {
4625ed0d50c3Schristos return (this->address()
4626ed0d50c3Schristos + this->first_plt_entry_offset()
4627ed0d50c3Schristos + this->count_ * this->get_plt_entry_size()
4628ed0d50c3Schristos + object->local_plt_offset(r_sym));
4629ed0d50c3Schristos }
4630ed0d50c3Schristos
4631ed0d50c3Schristos // Set the final size.
4632ed0d50c3Schristos
4633ed0d50c3Schristos template<int size, bool big_endian>
4634ed0d50c3Schristos void
set_final_data_size()4635ed0d50c3Schristos Output_data_plt_aarch64<size, big_endian>::set_final_data_size()
4636ed0d50c3Schristos {
4637ed0d50c3Schristos unsigned int count = this->count_ + this->irelative_count_;
4638ed0d50c3Schristos unsigned int extra_size = 0;
4639ed0d50c3Schristos if (this->has_tlsdesc_entry())
4640ed0d50c3Schristos extra_size += this->get_plt_tlsdesc_entry_size();
4641ed0d50c3Schristos this->set_data_size(this->first_plt_entry_offset()
4642ed0d50c3Schristos + count * this->get_plt_entry_size()
4643ed0d50c3Schristos + extra_size);
4644ed0d50c3Schristos }
4645ed0d50c3Schristos
4646ed0d50c3Schristos template<int size, bool big_endian>
4647ed0d50c3Schristos class Output_data_plt_aarch64_standard :
4648ed0d50c3Schristos public Output_data_plt_aarch64<size, big_endian>
4649ed0d50c3Schristos {
4650ed0d50c3Schristos public:
4651ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
Output_data_plt_aarch64_standard(Layout * layout,Output_data_got_aarch64<size,big_endian> * got,Output_data_space * got_plt,Output_data_space * got_irelative)4652ed0d50c3Schristos Output_data_plt_aarch64_standard(
4653ed0d50c3Schristos Layout* layout,
4654ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>* got,
4655ed0d50c3Schristos Output_data_space* got_plt,
4656ed0d50c3Schristos Output_data_space* got_irelative)
4657ed0d50c3Schristos : Output_data_plt_aarch64<size, big_endian>(layout,
4658ed0d50c3Schristos size == 32 ? 4 : 8,
4659ed0d50c3Schristos got, got_plt,
4660ed0d50c3Schristos got_irelative)
4661ed0d50c3Schristos { }
4662ed0d50c3Schristos
4663ed0d50c3Schristos protected:
4664ed0d50c3Schristos // Return the offset of the first non-reserved PLT entry.
4665ed0d50c3Schristos virtual unsigned int
do_first_plt_entry_offset() const4666ed0d50c3Schristos do_first_plt_entry_offset() const
4667ed0d50c3Schristos { return this->first_plt_entry_size; }
4668ed0d50c3Schristos
4669ed0d50c3Schristos // Return the size of a PLT entry
4670ed0d50c3Schristos virtual unsigned int
do_get_plt_entry_size() const4671ed0d50c3Schristos do_get_plt_entry_size() const
4672ed0d50c3Schristos { return this->plt_entry_size; }
4673ed0d50c3Schristos
4674ed0d50c3Schristos // Return the size of a tlsdesc entry
4675ed0d50c3Schristos virtual unsigned int
do_get_plt_tlsdesc_entry_size() const4676ed0d50c3Schristos do_get_plt_tlsdesc_entry_size() const
4677ed0d50c3Schristos { return this->plt_tlsdesc_entry_size; }
4678ed0d50c3Schristos
4679ed0d50c3Schristos virtual void
4680ed0d50c3Schristos do_fill_first_plt_entry(unsigned char* pov,
4681ed0d50c3Schristos Address got_address,
4682ed0d50c3Schristos Address plt_address);
4683ed0d50c3Schristos
4684ed0d50c3Schristos virtual void
4685ed0d50c3Schristos do_fill_plt_entry(unsigned char* pov,
4686ed0d50c3Schristos Address got_address,
4687ed0d50c3Schristos Address plt_address,
4688ed0d50c3Schristos unsigned int got_offset,
4689ed0d50c3Schristos unsigned int plt_offset);
4690ed0d50c3Schristos
4691ed0d50c3Schristos virtual void
4692ed0d50c3Schristos do_fill_tlsdesc_entry(unsigned char* pov,
4693ed0d50c3Schristos Address gotplt_address,
4694ed0d50c3Schristos Address plt_address,
4695ed0d50c3Schristos Address got_base,
4696ed0d50c3Schristos unsigned int tlsdesc_got_offset,
4697ed0d50c3Schristos unsigned int plt_offset);
4698ed0d50c3Schristos
4699ed0d50c3Schristos private:
4700ed0d50c3Schristos // The size of the first plt entry size.
4701ed0d50c3Schristos static const int first_plt_entry_size = 32;
4702ed0d50c3Schristos // The size of the plt entry size.
4703ed0d50c3Schristos static const int plt_entry_size = 16;
4704ed0d50c3Schristos // The size of the plt tlsdesc entry size.
4705ed0d50c3Schristos static const int plt_tlsdesc_entry_size = 32;
4706ed0d50c3Schristos // Template for the first PLT entry.
4707ed0d50c3Schristos static const uint32_t first_plt_entry[first_plt_entry_size / 4];
4708ed0d50c3Schristos // Template for subsequent PLT entries.
4709ed0d50c3Schristos static const uint32_t plt_entry[plt_entry_size / 4];
4710ed0d50c3Schristos // The reserved TLSDESC entry in the PLT for an executable.
4711ed0d50c3Schristos static const uint32_t tlsdesc_plt_entry[plt_tlsdesc_entry_size / 4];
4712ed0d50c3Schristos };
4713ed0d50c3Schristos
4714ed0d50c3Schristos // The first entry in the PLT for an executable.
4715ed0d50c3Schristos
4716ed0d50c3Schristos template<>
4717ed0d50c3Schristos const uint32_t
4718ed0d50c3Schristos Output_data_plt_aarch64_standard<32, false>::
4719ed0d50c3Schristos first_plt_entry[first_plt_entry_size / 4] =
4720ed0d50c3Schristos {
4721ed0d50c3Schristos 0xa9bf7bf0, /* stp x16, x30, [sp, #-16]! */
4722ed0d50c3Schristos 0x90000010, /* adrp x16, PLT_GOT+0x8 */
4723ed0d50c3Schristos 0xb9400A11, /* ldr w17, [x16, #PLT_GOT+0x8] */
4724ed0d50c3Schristos 0x11002210, /* add w16, w16,#PLT_GOT+0x8 */
4725ed0d50c3Schristos 0xd61f0220, /* br x17 */
4726ed0d50c3Schristos 0xd503201f, /* nop */
4727ed0d50c3Schristos 0xd503201f, /* nop */
4728ed0d50c3Schristos 0xd503201f, /* nop */
4729ed0d50c3Schristos };
4730ed0d50c3Schristos
4731ed0d50c3Schristos
4732ed0d50c3Schristos template<>
4733ed0d50c3Schristos const uint32_t
4734ed0d50c3Schristos Output_data_plt_aarch64_standard<32, true>::
4735ed0d50c3Schristos first_plt_entry[first_plt_entry_size / 4] =
4736ed0d50c3Schristos {
4737ed0d50c3Schristos 0xa9bf7bf0, /* stp x16, x30, [sp, #-16]! */
4738ed0d50c3Schristos 0x90000010, /* adrp x16, PLT_GOT+0x8 */
4739ed0d50c3Schristos 0xb9400A11, /* ldr w17, [x16, #PLT_GOT+0x8] */
4740ed0d50c3Schristos 0x11002210, /* add w16, w16,#PLT_GOT+0x8 */
4741ed0d50c3Schristos 0xd61f0220, /* br x17 */
4742ed0d50c3Schristos 0xd503201f, /* nop */
4743ed0d50c3Schristos 0xd503201f, /* nop */
4744ed0d50c3Schristos 0xd503201f, /* nop */
4745ed0d50c3Schristos };
4746ed0d50c3Schristos
4747ed0d50c3Schristos
4748ed0d50c3Schristos template<>
4749ed0d50c3Schristos const uint32_t
4750ed0d50c3Schristos Output_data_plt_aarch64_standard<64, false>::
4751ed0d50c3Schristos first_plt_entry[first_plt_entry_size / 4] =
4752ed0d50c3Schristos {
4753ed0d50c3Schristos 0xa9bf7bf0, /* stp x16, x30, [sp, #-16]! */
4754ed0d50c3Schristos 0x90000010, /* adrp x16, PLT_GOT+16 */
4755ed0d50c3Schristos 0xf9400A11, /* ldr x17, [x16, #PLT_GOT+0x10] */
4756ed0d50c3Schristos 0x91004210, /* add x16, x16,#PLT_GOT+0x10 */
4757ed0d50c3Schristos 0xd61f0220, /* br x17 */
4758ed0d50c3Schristos 0xd503201f, /* nop */
4759ed0d50c3Schristos 0xd503201f, /* nop */
4760ed0d50c3Schristos 0xd503201f, /* nop */
4761ed0d50c3Schristos };
4762ed0d50c3Schristos
4763ed0d50c3Schristos
4764ed0d50c3Schristos template<>
4765ed0d50c3Schristos const uint32_t
4766ed0d50c3Schristos Output_data_plt_aarch64_standard<64, true>::
4767ed0d50c3Schristos first_plt_entry[first_plt_entry_size / 4] =
4768ed0d50c3Schristos {
4769ed0d50c3Schristos 0xa9bf7bf0, /* stp x16, x30, [sp, #-16]! */
4770ed0d50c3Schristos 0x90000010, /* adrp x16, PLT_GOT+16 */
4771ed0d50c3Schristos 0xf9400A11, /* ldr x17, [x16, #PLT_GOT+0x10] */
4772ed0d50c3Schristos 0x91004210, /* add x16, x16,#PLT_GOT+0x10 */
4773ed0d50c3Schristos 0xd61f0220, /* br x17 */
4774ed0d50c3Schristos 0xd503201f, /* nop */
4775ed0d50c3Schristos 0xd503201f, /* nop */
4776ed0d50c3Schristos 0xd503201f, /* nop */
4777ed0d50c3Schristos };
4778ed0d50c3Schristos
4779ed0d50c3Schristos
4780ed0d50c3Schristos template<>
4781ed0d50c3Schristos const uint32_t
4782ed0d50c3Schristos Output_data_plt_aarch64_standard<32, false>::
4783ed0d50c3Schristos plt_entry[plt_entry_size / 4] =
4784ed0d50c3Schristos {
4785ed0d50c3Schristos 0x90000010, /* adrp x16, PLTGOT + n * 4 */
4786ed0d50c3Schristos 0xb9400211, /* ldr w17, [w16, PLTGOT + n * 4] */
4787ed0d50c3Schristos 0x11000210, /* add w16, w16, :lo12:PLTGOT + n * 4 */
4788ed0d50c3Schristos 0xd61f0220, /* br x17. */
4789ed0d50c3Schristos };
4790ed0d50c3Schristos
4791ed0d50c3Schristos
4792ed0d50c3Schristos template<>
4793ed0d50c3Schristos const uint32_t
4794ed0d50c3Schristos Output_data_plt_aarch64_standard<32, true>::
4795ed0d50c3Schristos plt_entry[plt_entry_size / 4] =
4796ed0d50c3Schristos {
4797ed0d50c3Schristos 0x90000010, /* adrp x16, PLTGOT + n * 4 */
4798ed0d50c3Schristos 0xb9400211, /* ldr w17, [w16, PLTGOT + n * 4] */
4799ed0d50c3Schristos 0x11000210, /* add w16, w16, :lo12:PLTGOT + n * 4 */
4800ed0d50c3Schristos 0xd61f0220, /* br x17. */
4801ed0d50c3Schristos };
4802ed0d50c3Schristos
4803ed0d50c3Schristos
4804ed0d50c3Schristos template<>
4805ed0d50c3Schristos const uint32_t
4806ed0d50c3Schristos Output_data_plt_aarch64_standard<64, false>::
4807ed0d50c3Schristos plt_entry[plt_entry_size / 4] =
4808ed0d50c3Schristos {
4809ed0d50c3Schristos 0x90000010, /* adrp x16, PLTGOT + n * 8 */
4810ed0d50c3Schristos 0xf9400211, /* ldr x17, [x16, PLTGOT + n * 8] */
4811ed0d50c3Schristos 0x91000210, /* add x16, x16, :lo12:PLTGOT + n * 8 */
4812ed0d50c3Schristos 0xd61f0220, /* br x17. */
4813ed0d50c3Schristos };
4814ed0d50c3Schristos
4815ed0d50c3Schristos
4816ed0d50c3Schristos template<>
4817ed0d50c3Schristos const uint32_t
4818ed0d50c3Schristos Output_data_plt_aarch64_standard<64, true>::
4819ed0d50c3Schristos plt_entry[plt_entry_size / 4] =
4820ed0d50c3Schristos {
4821ed0d50c3Schristos 0x90000010, /* adrp x16, PLTGOT + n * 8 */
4822ed0d50c3Schristos 0xf9400211, /* ldr x17, [x16, PLTGOT + n * 8] */
4823ed0d50c3Schristos 0x91000210, /* add x16, x16, :lo12:PLTGOT + n * 8 */
4824ed0d50c3Schristos 0xd61f0220, /* br x17. */
4825ed0d50c3Schristos };
4826ed0d50c3Schristos
4827ed0d50c3Schristos
4828ed0d50c3Schristos template<int size, bool big_endian>
4829ed0d50c3Schristos void
do_fill_first_plt_entry(unsigned char * pov,Address got_address,Address plt_address)4830ed0d50c3Schristos Output_data_plt_aarch64_standard<size, big_endian>::do_fill_first_plt_entry(
4831ed0d50c3Schristos unsigned char* pov,
4832ed0d50c3Schristos Address got_address,
4833ed0d50c3Schristos Address plt_address)
4834ed0d50c3Schristos {
4835ed0d50c3Schristos // PLT0 of the small PLT looks like this in ELF64 -
4836ed0d50c3Schristos // stp x16, x30, [sp, #-16]! Save the reloc and lr on stack.
4837ed0d50c3Schristos // adrp x16, PLT_GOT + 16 Get the page base of the GOTPLT
4838ed0d50c3Schristos // ldr x17, [x16, #:lo12:PLT_GOT+16] Load the address of the
4839ed0d50c3Schristos // symbol resolver
4840ed0d50c3Schristos // add x16, x16, #:lo12:PLT_GOT+16 Load the lo12 bits of the
4841ed0d50c3Schristos // GOTPLT entry for this.
4842ed0d50c3Schristos // br x17
4843ed0d50c3Schristos // PLT0 will be slightly different in ELF32 due to different got entry
4844ed0d50c3Schristos // size.
4845ed0d50c3Schristos memcpy(pov, this->first_plt_entry, this->first_plt_entry_size);
4846ed0d50c3Schristos Address gotplt_2nd_ent = got_address + (size / 8) * 2;
4847ed0d50c3Schristos
4848ed0d50c3Schristos // Fill in the top 21 bits for this: ADRP x16, PLT_GOT + 8 * 2.
4849ed0d50c3Schristos // ADRP: (PG(S+A)-PG(P)) >> 12) & 0x1fffff.
4850ed0d50c3Schristos // FIXME: This only works for 64bit
4851ed0d50c3Schristos AArch64_relocate_functions<size, big_endian>::adrp(pov + 4,
4852ed0d50c3Schristos gotplt_2nd_ent, plt_address + 4);
4853ed0d50c3Schristos
4854ed0d50c3Schristos // Fill in R_AARCH64_LDST8_LO12
4855ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(
4856ed0d50c3Schristos pov + 8,
4857ed0d50c3Schristos ((this->first_plt_entry[2] & 0xffc003ff)
4858ed0d50c3Schristos | ((gotplt_2nd_ent & 0xff8) << 7)));
4859ed0d50c3Schristos
4860ed0d50c3Schristos // Fill in R_AARCH64_ADD_ABS_LO12
4861ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(
4862ed0d50c3Schristos pov + 12,
4863ed0d50c3Schristos ((this->first_plt_entry[3] & 0xffc003ff)
4864ed0d50c3Schristos | ((gotplt_2nd_ent & 0xfff) << 10)));
4865ed0d50c3Schristos }
4866ed0d50c3Schristos
4867ed0d50c3Schristos
4868ed0d50c3Schristos // Subsequent entries in the PLT for an executable.
4869ed0d50c3Schristos // FIXME: This only works for 64bit
4870ed0d50c3Schristos
4871ed0d50c3Schristos template<int size, bool big_endian>
4872ed0d50c3Schristos void
do_fill_plt_entry(unsigned char * pov,Address got_address,Address plt_address,unsigned int got_offset,unsigned int plt_offset)4873ed0d50c3Schristos Output_data_plt_aarch64_standard<size, big_endian>::do_fill_plt_entry(
4874ed0d50c3Schristos unsigned char* pov,
4875ed0d50c3Schristos Address got_address,
4876ed0d50c3Schristos Address plt_address,
4877ed0d50c3Schristos unsigned int got_offset,
4878ed0d50c3Schristos unsigned int plt_offset)
4879ed0d50c3Schristos {
4880ed0d50c3Schristos memcpy(pov, this->plt_entry, this->plt_entry_size);
4881ed0d50c3Schristos
4882ed0d50c3Schristos Address gotplt_entry_address = got_address + got_offset;
4883ed0d50c3Schristos Address plt_entry_address = plt_address + plt_offset;
4884ed0d50c3Schristos
4885ed0d50c3Schristos // Fill in R_AARCH64_PCREL_ADR_HI21
4886ed0d50c3Schristos AArch64_relocate_functions<size, big_endian>::adrp(
4887ed0d50c3Schristos pov,
4888ed0d50c3Schristos gotplt_entry_address,
4889ed0d50c3Schristos plt_entry_address);
4890ed0d50c3Schristos
4891ed0d50c3Schristos // Fill in R_AARCH64_LDST64_ABS_LO12
4892ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(
4893ed0d50c3Schristos pov + 4,
4894ed0d50c3Schristos ((this->plt_entry[1] & 0xffc003ff)
4895ed0d50c3Schristos | ((gotplt_entry_address & 0xff8) << 7)));
4896ed0d50c3Schristos
4897ed0d50c3Schristos // Fill in R_AARCH64_ADD_ABS_LO12
4898ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(
4899ed0d50c3Schristos pov + 8,
4900ed0d50c3Schristos ((this->plt_entry[2] & 0xffc003ff)
4901ed0d50c3Schristos | ((gotplt_entry_address & 0xfff) <<10)));
4902ed0d50c3Schristos
4903ed0d50c3Schristos }
4904ed0d50c3Schristos
4905ed0d50c3Schristos
4906ed0d50c3Schristos template<>
4907ed0d50c3Schristos const uint32_t
4908ed0d50c3Schristos Output_data_plt_aarch64_standard<32, false>::
4909ed0d50c3Schristos tlsdesc_plt_entry[plt_tlsdesc_entry_size / 4] =
4910ed0d50c3Schristos {
4911ed0d50c3Schristos 0xa9bf0fe2, /* stp x2, x3, [sp, #-16]! */
4912ed0d50c3Schristos 0x90000002, /* adrp x2, 0 */
4913ed0d50c3Schristos 0x90000003, /* adrp x3, 0 */
4914ed0d50c3Schristos 0xb9400042, /* ldr w2, [w2, #0] */
4915ed0d50c3Schristos 0x11000063, /* add w3, w3, 0 */
4916ed0d50c3Schristos 0xd61f0040, /* br x2 */
4917ed0d50c3Schristos 0xd503201f, /* nop */
4918ed0d50c3Schristos 0xd503201f, /* nop */
4919ed0d50c3Schristos };
4920ed0d50c3Schristos
4921ed0d50c3Schristos template<>
4922ed0d50c3Schristos const uint32_t
4923ed0d50c3Schristos Output_data_plt_aarch64_standard<32, true>::
4924ed0d50c3Schristos tlsdesc_plt_entry[plt_tlsdesc_entry_size / 4] =
4925ed0d50c3Schristos {
4926ed0d50c3Schristos 0xa9bf0fe2, /* stp x2, x3, [sp, #-16]! */
4927ed0d50c3Schristos 0x90000002, /* adrp x2, 0 */
4928ed0d50c3Schristos 0x90000003, /* adrp x3, 0 */
4929ed0d50c3Schristos 0xb9400042, /* ldr w2, [w2, #0] */
4930ed0d50c3Schristos 0x11000063, /* add w3, w3, 0 */
4931ed0d50c3Schristos 0xd61f0040, /* br x2 */
4932ed0d50c3Schristos 0xd503201f, /* nop */
4933ed0d50c3Schristos 0xd503201f, /* nop */
4934ed0d50c3Schristos };
4935ed0d50c3Schristos
4936ed0d50c3Schristos template<>
4937ed0d50c3Schristos const uint32_t
4938ed0d50c3Schristos Output_data_plt_aarch64_standard<64, false>::
4939ed0d50c3Schristos tlsdesc_plt_entry[plt_tlsdesc_entry_size / 4] =
4940ed0d50c3Schristos {
4941ed0d50c3Schristos 0xa9bf0fe2, /* stp x2, x3, [sp, #-16]! */
4942ed0d50c3Schristos 0x90000002, /* adrp x2, 0 */
4943ed0d50c3Schristos 0x90000003, /* adrp x3, 0 */
4944ed0d50c3Schristos 0xf9400042, /* ldr x2, [x2, #0] */
4945ed0d50c3Schristos 0x91000063, /* add x3, x3, 0 */
4946ed0d50c3Schristos 0xd61f0040, /* br x2 */
4947ed0d50c3Schristos 0xd503201f, /* nop */
4948ed0d50c3Schristos 0xd503201f, /* nop */
4949ed0d50c3Schristos };
4950ed0d50c3Schristos
4951ed0d50c3Schristos template<>
4952ed0d50c3Schristos const uint32_t
4953ed0d50c3Schristos Output_data_plt_aarch64_standard<64, true>::
4954ed0d50c3Schristos tlsdesc_plt_entry[plt_tlsdesc_entry_size / 4] =
4955ed0d50c3Schristos {
4956ed0d50c3Schristos 0xa9bf0fe2, /* stp x2, x3, [sp, #-16]! */
4957ed0d50c3Schristos 0x90000002, /* adrp x2, 0 */
4958ed0d50c3Schristos 0x90000003, /* adrp x3, 0 */
4959ed0d50c3Schristos 0xf9400042, /* ldr x2, [x2, #0] */
4960ed0d50c3Schristos 0x91000063, /* add x3, x3, 0 */
4961ed0d50c3Schristos 0xd61f0040, /* br x2 */
4962ed0d50c3Schristos 0xd503201f, /* nop */
4963ed0d50c3Schristos 0xd503201f, /* nop */
4964ed0d50c3Schristos };
4965ed0d50c3Schristos
4966ed0d50c3Schristos template<int size, bool big_endian>
4967ed0d50c3Schristos void
do_fill_tlsdesc_entry(unsigned char * pov,Address gotplt_address,Address plt_address,Address got_base,unsigned int tlsdesc_got_offset,unsigned int plt_offset)4968ed0d50c3Schristos Output_data_plt_aarch64_standard<size, big_endian>::do_fill_tlsdesc_entry(
4969ed0d50c3Schristos unsigned char* pov,
4970ed0d50c3Schristos Address gotplt_address,
4971ed0d50c3Schristos Address plt_address,
4972ed0d50c3Schristos Address got_base,
4973ed0d50c3Schristos unsigned int tlsdesc_got_offset,
4974ed0d50c3Schristos unsigned int plt_offset)
4975ed0d50c3Schristos {
4976ed0d50c3Schristos memcpy(pov, tlsdesc_plt_entry, plt_tlsdesc_entry_size);
4977ed0d50c3Schristos
4978ed0d50c3Schristos // move DT_TLSDESC_GOT address into x2
4979ed0d50c3Schristos // move .got.plt address into x3
4980ed0d50c3Schristos Address tlsdesc_got_entry = got_base + tlsdesc_got_offset;
4981ed0d50c3Schristos Address plt_entry_address = plt_address + plt_offset;
4982ed0d50c3Schristos
4983ed0d50c3Schristos // R_AARCH64_ADR_PREL_PG_HI21
4984ed0d50c3Schristos AArch64_relocate_functions<size, big_endian>::adrp(
4985ed0d50c3Schristos pov + 4,
4986ed0d50c3Schristos tlsdesc_got_entry,
4987ed0d50c3Schristos plt_entry_address + 4);
4988ed0d50c3Schristos
4989ed0d50c3Schristos // R_AARCH64_ADR_PREL_PG_HI21
4990ed0d50c3Schristos AArch64_relocate_functions<size, big_endian>::adrp(
4991ed0d50c3Schristos pov + 8,
4992ed0d50c3Schristos gotplt_address,
4993ed0d50c3Schristos plt_entry_address + 8);
4994ed0d50c3Schristos
4995ed0d50c3Schristos // R_AARCH64_LDST64_ABS_LO12
4996ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(
4997ed0d50c3Schristos pov + 12,
4998ed0d50c3Schristos ((this->tlsdesc_plt_entry[3] & 0xffc003ff)
4999ed0d50c3Schristos | ((tlsdesc_got_entry & 0xff8) << 7)));
5000ed0d50c3Schristos
5001ed0d50c3Schristos // R_AARCH64_ADD_ABS_LO12
5002ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(
5003ed0d50c3Schristos pov + 16,
5004ed0d50c3Schristos ((this->tlsdesc_plt_entry[4] & 0xffc003ff)
5005ed0d50c3Schristos | ((gotplt_address & 0xfff) << 10)));
5006ed0d50c3Schristos }
5007ed0d50c3Schristos
5008ed0d50c3Schristos // Write out the PLT. This uses the hand-coded instructions above,
5009ed0d50c3Schristos // and adjusts them as needed. This is specified by the AMD64 ABI.
5010ed0d50c3Schristos
5011ed0d50c3Schristos template<int size, bool big_endian>
5012ed0d50c3Schristos void
do_write(Output_file * of)5013ed0d50c3Schristos Output_data_plt_aarch64<size, big_endian>::do_write(Output_file* of)
5014ed0d50c3Schristos {
5015ed0d50c3Schristos const off_t offset = this->offset();
5016ed0d50c3Schristos const section_size_type oview_size =
5017ed0d50c3Schristos convert_to_section_size_type(this->data_size());
5018ed0d50c3Schristos unsigned char* const oview = of->get_output_view(offset, oview_size);
5019ed0d50c3Schristos
5020ed0d50c3Schristos const off_t got_file_offset = this->got_plt_->offset();
5021ed0d50c3Schristos gold_assert(got_file_offset + this->got_plt_->data_size()
5022ed0d50c3Schristos == this->got_irelative_->offset());
5023ed0d50c3Schristos
5024ed0d50c3Schristos const section_size_type got_size =
5025ed0d50c3Schristos convert_to_section_size_type(this->got_plt_->data_size()
5026ed0d50c3Schristos + this->got_irelative_->data_size());
5027ed0d50c3Schristos unsigned char* const got_view = of->get_output_view(got_file_offset,
5028ed0d50c3Schristos got_size);
5029ed0d50c3Schristos
5030ed0d50c3Schristos unsigned char* pov = oview;
5031ed0d50c3Schristos
5032ed0d50c3Schristos // The base address of the .plt section.
5033ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr plt_address = this->address();
5034ed0d50c3Schristos // The base address of the PLT portion of the .got section.
5035ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr gotplt_address
5036ed0d50c3Schristos = this->got_plt_->address();
5037ed0d50c3Schristos
5038ed0d50c3Schristos this->fill_first_plt_entry(pov, gotplt_address, plt_address);
5039ed0d50c3Schristos pov += this->first_plt_entry_offset();
5040ed0d50c3Schristos
5041ed0d50c3Schristos // The first three entries in .got.plt are reserved.
5042ed0d50c3Schristos unsigned char* got_pov = got_view;
5043ed0d50c3Schristos memset(got_pov, 0, size / 8 * AARCH64_GOTPLT_RESERVE_COUNT);
5044ed0d50c3Schristos got_pov += (size / 8) * AARCH64_GOTPLT_RESERVE_COUNT;
5045ed0d50c3Schristos
5046ed0d50c3Schristos unsigned int plt_offset = this->first_plt_entry_offset();
5047ed0d50c3Schristos unsigned int got_offset = (size / 8) * AARCH64_GOTPLT_RESERVE_COUNT;
5048ed0d50c3Schristos const unsigned int count = this->count_ + this->irelative_count_;
5049ed0d50c3Schristos for (unsigned int plt_index = 0;
5050ed0d50c3Schristos plt_index < count;
5051ed0d50c3Schristos ++plt_index,
5052ed0d50c3Schristos pov += this->get_plt_entry_size(),
5053ed0d50c3Schristos got_pov += size / 8,
5054ed0d50c3Schristos plt_offset += this->get_plt_entry_size(),
5055ed0d50c3Schristos got_offset += size / 8)
5056ed0d50c3Schristos {
5057ed0d50c3Schristos // Set and adjust the PLT entry itself.
5058ed0d50c3Schristos this->fill_plt_entry(pov, gotplt_address, plt_address,
5059ed0d50c3Schristos got_offset, plt_offset);
5060ed0d50c3Schristos
5061ed0d50c3Schristos // Set the entry in the GOT, which points to plt0.
5062ed0d50c3Schristos elfcpp::Swap<size, big_endian>::writeval(got_pov, plt_address);
5063ed0d50c3Schristos }
5064ed0d50c3Schristos
5065ed0d50c3Schristos if (this->has_tlsdesc_entry())
5066ed0d50c3Schristos {
5067ed0d50c3Schristos // Set and adjust the reserved TLSDESC PLT entry.
5068ed0d50c3Schristos unsigned int tlsdesc_got_offset = this->get_tlsdesc_got_offset();
5069ed0d50c3Schristos // The base address of the .base section.
5070ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr got_base =
5071ed0d50c3Schristos this->got_->address();
5072ed0d50c3Schristos this->fill_tlsdesc_entry(pov, gotplt_address, plt_address, got_base,
5073ed0d50c3Schristos tlsdesc_got_offset, plt_offset);
5074ed0d50c3Schristos pov += this->get_plt_tlsdesc_entry_size();
5075ed0d50c3Schristos }
5076ed0d50c3Schristos
5077ed0d50c3Schristos gold_assert(static_cast<section_size_type>(pov - oview) == oview_size);
5078ed0d50c3Schristos gold_assert(static_cast<section_size_type>(got_pov - got_view) == got_size);
5079ed0d50c3Schristos
5080ed0d50c3Schristos of->write_output_view(offset, oview_size, oview);
5081ed0d50c3Schristos of->write_output_view(got_file_offset, got_size, got_view);
5082ed0d50c3Schristos }
5083ed0d50c3Schristos
5084ed0d50c3Schristos // Telling how to update the immediate field of an instruction.
5085ed0d50c3Schristos struct AArch64_howto
5086ed0d50c3Schristos {
5087ed0d50c3Schristos // The immediate field mask.
5088ed0d50c3Schristos elfcpp::Elf_Xword dst_mask;
5089ed0d50c3Schristos
5090ed0d50c3Schristos // The offset to apply relocation immediate
5091ed0d50c3Schristos int doffset;
5092ed0d50c3Schristos
5093ed0d50c3Schristos // The second part offset, if the immediate field has two parts.
5094ed0d50c3Schristos // -1 if the immediate field has only one part.
5095ed0d50c3Schristos int doffset2;
5096ed0d50c3Schristos };
5097ed0d50c3Schristos
5098ed0d50c3Schristos static const AArch64_howto aarch64_howto[AArch64_reloc_property::INST_NUM] =
5099ed0d50c3Schristos {
5100ed0d50c3Schristos {0, -1, -1}, // DATA
5101ed0d50c3Schristos {0x1fffe0, 5, -1}, // MOVW [20:5]-imm16
5102ed0d50c3Schristos {0xffffe0, 5, -1}, // LD [23:5]-imm19
5103ed0d50c3Schristos {0x60ffffe0, 29, 5}, // ADR [30:29]-immlo [23:5]-immhi
5104ed0d50c3Schristos {0x60ffffe0, 29, 5}, // ADRP [30:29]-immlo [23:5]-immhi
5105ed0d50c3Schristos {0x3ffc00, 10, -1}, // ADD [21:10]-imm12
5106ed0d50c3Schristos {0x3ffc00, 10, -1}, // LDST [21:10]-imm12
5107ed0d50c3Schristos {0x7ffe0, 5, -1}, // TBZNZ [18:5]-imm14
5108ed0d50c3Schristos {0xffffe0, 5, -1}, // CONDB [23:5]-imm19
5109ed0d50c3Schristos {0x3ffffff, 0, -1}, // B [25:0]-imm26
5110ed0d50c3Schristos {0x3ffffff, 0, -1}, // CALL [25:0]-imm26
5111ed0d50c3Schristos };
5112ed0d50c3Schristos
5113ed0d50c3Schristos // AArch64 relocate function class
5114ed0d50c3Schristos
5115ed0d50c3Schristos template<int size, bool big_endian>
5116ed0d50c3Schristos class AArch64_relocate_functions
5117ed0d50c3Schristos {
5118ed0d50c3Schristos public:
5119ed0d50c3Schristos typedef enum
5120ed0d50c3Schristos {
5121ed0d50c3Schristos STATUS_OKAY, // No error during relocation.
5122ed0d50c3Schristos STATUS_OVERFLOW, // Relocation overflow.
5123ed0d50c3Schristos STATUS_BAD_RELOC, // Relocation cannot be applied.
5124ed0d50c3Schristos } Status;
5125ed0d50c3Schristos
5126ed0d50c3Schristos typedef AArch64_relocate_functions<size, big_endian> This;
5127ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
5128ed0d50c3Schristos typedef Relocate_info<size, big_endian> The_relocate_info;
5129ed0d50c3Schristos typedef AArch64_relobj<size, big_endian> The_aarch64_relobj;
5130ed0d50c3Schristos typedef Reloc_stub<size, big_endian> The_reloc_stub;
5131ed0d50c3Schristos typedef Stub_table<size, big_endian> The_stub_table;
5132ed0d50c3Schristos typedef elfcpp::Rela<size, big_endian> The_rela;
5133ed0d50c3Schristos typedef typename elfcpp::Swap<size, big_endian>::Valtype AArch64_valtype;
5134ed0d50c3Schristos
5135ed0d50c3Schristos // Return the page address of the address.
5136ed0d50c3Schristos // Page(address) = address & ~0xFFF
5137ed0d50c3Schristos
5138ed0d50c3Schristos static inline AArch64_valtype
Page(Address address)5139ed0d50c3Schristos Page(Address address)
5140ed0d50c3Schristos {
5141ed0d50c3Schristos return (address & (~static_cast<Address>(0xFFF)));
5142ed0d50c3Schristos }
5143ed0d50c3Schristos
5144ed0d50c3Schristos private:
5145ed0d50c3Schristos // Update instruction (pointed by view) with selected bits (immed).
5146ed0d50c3Schristos // val = (val & ~dst_mask) | (immed << doffset)
5147ed0d50c3Schristos
5148ed0d50c3Schristos template<int valsize>
5149ed0d50c3Schristos static inline void
update_view(unsigned char * view,AArch64_valtype immed,elfcpp::Elf_Xword doffset,elfcpp::Elf_Xword dst_mask)5150ed0d50c3Schristos update_view(unsigned char* view,
5151ed0d50c3Schristos AArch64_valtype immed,
5152ed0d50c3Schristos elfcpp::Elf_Xword doffset,
5153ed0d50c3Schristos elfcpp::Elf_Xword dst_mask)
5154ed0d50c3Schristos {
5155ed0d50c3Schristos typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
5156ed0d50c3Schristos Valtype* wv = reinterpret_cast<Valtype*>(view);
5157ed0d50c3Schristos Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
5158ed0d50c3Schristos
5159ed0d50c3Schristos // Clear immediate fields.
5160ed0d50c3Schristos val &= ~dst_mask;
5161ed0d50c3Schristos elfcpp::Swap<valsize, big_endian>::writeval(wv,
5162ed0d50c3Schristos static_cast<Valtype>(val | (immed << doffset)));
5163ed0d50c3Schristos }
5164ed0d50c3Schristos
5165ed0d50c3Schristos // Update two parts of an instruction (pointed by view) with selected
5166ed0d50c3Schristos // bits (immed1 and immed2).
5167ed0d50c3Schristos // val = (val & ~dst_mask) | (immed1 << doffset1) | (immed2 << doffset2)
5168ed0d50c3Schristos
5169ed0d50c3Schristos template<int valsize>
5170ed0d50c3Schristos static inline void
update_view_two_parts(unsigned char * view,AArch64_valtype immed1,AArch64_valtype immed2,elfcpp::Elf_Xword doffset1,elfcpp::Elf_Xword doffset2,elfcpp::Elf_Xword dst_mask)5171ed0d50c3Schristos update_view_two_parts(
5172ed0d50c3Schristos unsigned char* view,
5173ed0d50c3Schristos AArch64_valtype immed1,
5174ed0d50c3Schristos AArch64_valtype immed2,
5175ed0d50c3Schristos elfcpp::Elf_Xword doffset1,
5176ed0d50c3Schristos elfcpp::Elf_Xword doffset2,
5177ed0d50c3Schristos elfcpp::Elf_Xword dst_mask)
5178ed0d50c3Schristos {
5179ed0d50c3Schristos typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
5180ed0d50c3Schristos Valtype* wv = reinterpret_cast<Valtype*>(view);
5181ed0d50c3Schristos Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
5182ed0d50c3Schristos val &= ~dst_mask;
5183ed0d50c3Schristos elfcpp::Swap<valsize, big_endian>::writeval(wv,
5184ed0d50c3Schristos static_cast<Valtype>(val | (immed1 << doffset1) |
5185ed0d50c3Schristos (immed2 << doffset2)));
5186ed0d50c3Schristos }
5187ed0d50c3Schristos
5188ed0d50c3Schristos // Update adr or adrp instruction with immed.
5189ed0d50c3Schristos // In adr and adrp: [30:29] immlo [23:5] immhi
5190ed0d50c3Schristos
5191ed0d50c3Schristos static inline void
update_adr(unsigned char * view,AArch64_valtype immed)5192ed0d50c3Schristos update_adr(unsigned char* view, AArch64_valtype immed)
5193ed0d50c3Schristos {
5194ed0d50c3Schristos elfcpp::Elf_Xword dst_mask = (0x3 << 29) | (0x7ffff << 5);
5195ed0d50c3Schristos This::template update_view_two_parts<32>(
5196ed0d50c3Schristos view,
5197ed0d50c3Schristos immed & 0x3,
5198ed0d50c3Schristos (immed & 0x1ffffc) >> 2,
5199ed0d50c3Schristos 29,
5200ed0d50c3Schristos 5,
5201ed0d50c3Schristos dst_mask);
5202ed0d50c3Schristos }
5203ed0d50c3Schristos
5204ed0d50c3Schristos // Update movz/movn instruction with bits immed.
5205ed0d50c3Schristos // Set instruction to movz if is_movz is true, otherwise set instruction
5206ed0d50c3Schristos // to movn.
5207ed0d50c3Schristos
5208ed0d50c3Schristos static inline void
update_movnz(unsigned char * view,AArch64_valtype immed,bool is_movz)5209ed0d50c3Schristos update_movnz(unsigned char* view,
5210ed0d50c3Schristos AArch64_valtype immed,
5211ed0d50c3Schristos bool is_movz)
5212ed0d50c3Schristos {
5213ed0d50c3Schristos typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
5214ed0d50c3Schristos Valtype* wv = reinterpret_cast<Valtype*>(view);
5215ed0d50c3Schristos Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
5216ed0d50c3Schristos
5217ed0d50c3Schristos const elfcpp::Elf_Xword doffset =
5218ed0d50c3Schristos aarch64_howto[AArch64_reloc_property::INST_MOVW].doffset;
5219ed0d50c3Schristos const elfcpp::Elf_Xword dst_mask =
5220ed0d50c3Schristos aarch64_howto[AArch64_reloc_property::INST_MOVW].dst_mask;
5221ed0d50c3Schristos
5222ed0d50c3Schristos // Clear immediate fields and opc code.
5223ed0d50c3Schristos val &= ~(dst_mask | (0x3 << 29));
5224ed0d50c3Schristos
5225ed0d50c3Schristos // Set instruction to movz or movn.
5226ed0d50c3Schristos // movz: [30:29] is 10 movn: [30:29] is 00
5227ed0d50c3Schristos if (is_movz)
5228ed0d50c3Schristos val |= (0x2 << 29);
5229ed0d50c3Schristos
5230ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(wv,
5231ed0d50c3Schristos static_cast<Valtype>(val | (immed << doffset)));
5232ed0d50c3Schristos }
5233ed0d50c3Schristos
5234ed0d50c3Schristos public:
5235ed0d50c3Schristos
5236ed0d50c3Schristos // Update selected bits in text.
5237ed0d50c3Schristos
5238ed0d50c3Schristos template<int valsize>
5239ed0d50c3Schristos static inline typename This::Status
reloc_common(unsigned char * view,Address x,const AArch64_reloc_property * reloc_property)5240ed0d50c3Schristos reloc_common(unsigned char* view, Address x,
5241ed0d50c3Schristos const AArch64_reloc_property* reloc_property)
5242ed0d50c3Schristos {
5243ed0d50c3Schristos // Select bits from X.
5244ed0d50c3Schristos Address immed = reloc_property->select_x_value(x);
5245ed0d50c3Schristos
5246ed0d50c3Schristos // Update view.
5247ed0d50c3Schristos const AArch64_reloc_property::Reloc_inst inst =
5248ed0d50c3Schristos reloc_property->reloc_inst();
5249ed0d50c3Schristos // If it is a data relocation or instruction has 2 parts of immediate
5250ed0d50c3Schristos // fields, you should not call pcrela_general.
5251ed0d50c3Schristos gold_assert(aarch64_howto[inst].doffset2 == -1 &&
5252ed0d50c3Schristos aarch64_howto[inst].doffset != -1);
5253ed0d50c3Schristos This::template update_view<valsize>(view, immed,
5254ed0d50c3Schristos aarch64_howto[inst].doffset,
5255ed0d50c3Schristos aarch64_howto[inst].dst_mask);
5256ed0d50c3Schristos
5257ed0d50c3Schristos // Do check overflow or alignment if needed.
5258ed0d50c3Schristos return (reloc_property->checkup_x_value(x)
5259ed0d50c3Schristos ? This::STATUS_OKAY
5260ed0d50c3Schristos : This::STATUS_OVERFLOW);
5261ed0d50c3Schristos }
5262ed0d50c3Schristos
5263ed0d50c3Schristos // Construct a B insn. Note, although we group it here with other relocation
5264ed0d50c3Schristos // operation, there is actually no 'relocation' involved here.
5265ed0d50c3Schristos static inline void
construct_b(unsigned char * view,unsigned int branch_offset)5266ed0d50c3Schristos construct_b(unsigned char* view, unsigned int branch_offset)
5267ed0d50c3Schristos {
5268ed0d50c3Schristos update_view_two_parts<32>(view, 0x05, (branch_offset >> 2),
5269ed0d50c3Schristos 26, 0, 0xffffffff);
5270ed0d50c3Schristos }
5271ed0d50c3Schristos
5272ed0d50c3Schristos // Do a simple rela relocation at unaligned addresses.
5273ed0d50c3Schristos
5274ed0d50c3Schristos template<int valsize>
5275ed0d50c3Schristos static inline typename This::Status
rela_ua(unsigned char * view,const Sized_relobj_file<size,big_endian> * object,const Symbol_value<size> * psymval,AArch64_valtype addend,const AArch64_reloc_property * reloc_property)5276ed0d50c3Schristos rela_ua(unsigned char* view,
5277ed0d50c3Schristos const Sized_relobj_file<size, big_endian>* object,
5278ed0d50c3Schristos const Symbol_value<size>* psymval,
5279ed0d50c3Schristos AArch64_valtype addend,
5280ed0d50c3Schristos const AArch64_reloc_property* reloc_property)
5281ed0d50c3Schristos {
5282ed0d50c3Schristos typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
5283ed0d50c3Schristos Valtype;
5284ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr x =
5285ed0d50c3Schristos psymval->value(object, addend);
5286ed0d50c3Schristos elfcpp::Swap_unaligned<valsize, big_endian>::writeval(view,
5287ed0d50c3Schristos static_cast<Valtype>(x));
5288ed0d50c3Schristos return (reloc_property->checkup_x_value(x)
5289ed0d50c3Schristos ? This::STATUS_OKAY
5290ed0d50c3Schristos : This::STATUS_OVERFLOW);
5291ed0d50c3Schristos }
5292ed0d50c3Schristos
5293ed0d50c3Schristos // Do a simple pc-relative relocation at unaligned addresses.
5294ed0d50c3Schristos
5295ed0d50c3Schristos template<int valsize>
5296ed0d50c3Schristos static inline typename This::Status
pcrela_ua(unsigned char * view,const Sized_relobj_file<size,big_endian> * object,const Symbol_value<size> * psymval,AArch64_valtype addend,Address address,const AArch64_reloc_property * reloc_property)5297ed0d50c3Schristos pcrela_ua(unsigned char* view,
5298ed0d50c3Schristos const Sized_relobj_file<size, big_endian>* object,
5299ed0d50c3Schristos const Symbol_value<size>* psymval,
5300ed0d50c3Schristos AArch64_valtype addend,
5301ed0d50c3Schristos Address address,
5302ed0d50c3Schristos const AArch64_reloc_property* reloc_property)
5303ed0d50c3Schristos {
5304ed0d50c3Schristos typedef typename elfcpp::Swap_unaligned<valsize, big_endian>::Valtype
5305ed0d50c3Schristos Valtype;
5306ed0d50c3Schristos Address x = psymval->value(object, addend) - address;
5307ed0d50c3Schristos elfcpp::Swap_unaligned<valsize, big_endian>::writeval(view,
5308ed0d50c3Schristos static_cast<Valtype>(x));
5309ed0d50c3Schristos return (reloc_property->checkup_x_value(x)
5310ed0d50c3Schristos ? This::STATUS_OKAY
5311ed0d50c3Schristos : This::STATUS_OVERFLOW);
5312ed0d50c3Schristos }
5313ed0d50c3Schristos
5314ed0d50c3Schristos // Do a simple rela relocation at aligned addresses.
5315ed0d50c3Schristos
5316ed0d50c3Schristos template<int valsize>
5317ed0d50c3Schristos static inline typename This::Status
rela(unsigned char * view,const Sized_relobj_file<size,big_endian> * object,const Symbol_value<size> * psymval,AArch64_valtype addend,const AArch64_reloc_property * reloc_property)5318ed0d50c3Schristos rela(
5319ed0d50c3Schristos unsigned char* view,
5320ed0d50c3Schristos const Sized_relobj_file<size, big_endian>* object,
5321ed0d50c3Schristos const Symbol_value<size>* psymval,
5322ed0d50c3Schristos AArch64_valtype addend,
5323ed0d50c3Schristos const AArch64_reloc_property* reloc_property)
5324ed0d50c3Schristos {
5325ed0d50c3Schristos typedef typename elfcpp::Swap<valsize, big_endian>::Valtype Valtype;
5326ed0d50c3Schristos Valtype* wv = reinterpret_cast<Valtype*>(view);
5327ed0d50c3Schristos Address x = psymval->value(object, addend);
5328ed0d50c3Schristos elfcpp::Swap<valsize, big_endian>::writeval(wv,static_cast<Valtype>(x));
5329ed0d50c3Schristos return (reloc_property->checkup_x_value(x)
5330ed0d50c3Schristos ? This::STATUS_OKAY
5331ed0d50c3Schristos : This::STATUS_OVERFLOW);
5332ed0d50c3Schristos }
5333ed0d50c3Schristos
5334ed0d50c3Schristos // Do relocate. Update selected bits in text.
5335ed0d50c3Schristos // new_val = (val & ~dst_mask) | (immed << doffset)
5336ed0d50c3Schristos
5337ed0d50c3Schristos template<int valsize>
5338ed0d50c3Schristos static inline typename This::Status
rela_general(unsigned char * view,const Sized_relobj_file<size,big_endian> * object,const Symbol_value<size> * psymval,AArch64_valtype addend,const AArch64_reloc_property * reloc_property)5339ed0d50c3Schristos rela_general(unsigned char* view,
5340ed0d50c3Schristos const Sized_relobj_file<size, big_endian>* object,
5341ed0d50c3Schristos const Symbol_value<size>* psymval,
5342ed0d50c3Schristos AArch64_valtype addend,
5343ed0d50c3Schristos const AArch64_reloc_property* reloc_property)
5344ed0d50c3Schristos {
5345ed0d50c3Schristos // Calculate relocation.
5346ed0d50c3Schristos Address x = psymval->value(object, addend);
5347ed0d50c3Schristos return This::template reloc_common<valsize>(view, x, reloc_property);
5348ed0d50c3Schristos }
5349ed0d50c3Schristos
5350ed0d50c3Schristos // Do relocate. Update selected bits in text.
5351ed0d50c3Schristos // new val = (val & ~dst_mask) | (immed << doffset)
5352ed0d50c3Schristos
5353ed0d50c3Schristos template<int valsize>
5354ed0d50c3Schristos static inline typename This::Status
rela_general(unsigned char * view,AArch64_valtype s,AArch64_valtype addend,const AArch64_reloc_property * reloc_property)5355ed0d50c3Schristos rela_general(
5356ed0d50c3Schristos unsigned char* view,
5357ed0d50c3Schristos AArch64_valtype s,
5358ed0d50c3Schristos AArch64_valtype addend,
5359ed0d50c3Schristos const AArch64_reloc_property* reloc_property)
5360ed0d50c3Schristos {
5361ed0d50c3Schristos // Calculate relocation.
5362ed0d50c3Schristos Address x = s + addend;
5363ed0d50c3Schristos return This::template reloc_common<valsize>(view, x, reloc_property);
5364ed0d50c3Schristos }
5365ed0d50c3Schristos
5366ed0d50c3Schristos // Do address relative relocate. Update selected bits in text.
5367ed0d50c3Schristos // new val = (val & ~dst_mask) | (immed << doffset)
5368ed0d50c3Schristos
5369ed0d50c3Schristos template<int valsize>
5370ed0d50c3Schristos static inline typename This::Status
pcrela_general(unsigned char * view,const Sized_relobj_file<size,big_endian> * object,const Symbol_value<size> * psymval,AArch64_valtype addend,Address address,const AArch64_reloc_property * reloc_property)5371ed0d50c3Schristos pcrela_general(
5372ed0d50c3Schristos unsigned char* view,
5373ed0d50c3Schristos const Sized_relobj_file<size, big_endian>* object,
5374ed0d50c3Schristos const Symbol_value<size>* psymval,
5375ed0d50c3Schristos AArch64_valtype addend,
5376ed0d50c3Schristos Address address,
5377ed0d50c3Schristos const AArch64_reloc_property* reloc_property)
5378ed0d50c3Schristos {
5379ed0d50c3Schristos // Calculate relocation.
5380ed0d50c3Schristos Address x = psymval->value(object, addend) - address;
5381ed0d50c3Schristos return This::template reloc_common<valsize>(view, x, reloc_property);
5382ed0d50c3Schristos }
5383ed0d50c3Schristos
5384ed0d50c3Schristos
5385ed0d50c3Schristos // Calculate (S + A) - address, update adr instruction.
5386ed0d50c3Schristos
5387ed0d50c3Schristos static inline typename This::Status
adr(unsigned char * view,const Sized_relobj_file<size,big_endian> * object,const Symbol_value<size> * psymval,Address addend,Address address,const AArch64_reloc_property *)5388ed0d50c3Schristos adr(unsigned char* view,
5389ed0d50c3Schristos const Sized_relobj_file<size, big_endian>* object,
5390ed0d50c3Schristos const Symbol_value<size>* psymval,
5391ed0d50c3Schristos Address addend,
5392ed0d50c3Schristos Address address,
5393ed0d50c3Schristos const AArch64_reloc_property* /* reloc_property */)
5394ed0d50c3Schristos {
5395ed0d50c3Schristos AArch64_valtype x = psymval->value(object, addend) - address;
5396ed0d50c3Schristos // Pick bits [20:0] of X.
5397ed0d50c3Schristos AArch64_valtype immed = x & 0x1fffff;
5398ed0d50c3Schristos update_adr(view, immed);
5399ed0d50c3Schristos // Check -2^20 <= X < 2^20
5400ed0d50c3Schristos return (size == 64 && Bits<21>::has_overflow((x))
5401ed0d50c3Schristos ? This::STATUS_OVERFLOW
5402ed0d50c3Schristos : This::STATUS_OKAY);
5403ed0d50c3Schristos }
5404ed0d50c3Schristos
5405ed0d50c3Schristos // Calculate PG(S+A) - PG(address), update adrp instruction.
5406ed0d50c3Schristos // R_AARCH64_ADR_PREL_PG_HI21
5407ed0d50c3Schristos
5408ed0d50c3Schristos static inline typename This::Status
adrp(unsigned char * view,Address sa,Address address)5409ed0d50c3Schristos adrp(
5410ed0d50c3Schristos unsigned char* view,
5411ed0d50c3Schristos Address sa,
5412ed0d50c3Schristos Address address)
5413ed0d50c3Schristos {
5414ed0d50c3Schristos AArch64_valtype x = This::Page(sa) - This::Page(address);
5415ed0d50c3Schristos // Pick [32:12] of X.
5416ed0d50c3Schristos AArch64_valtype immed = (x >> 12) & 0x1fffff;
5417ed0d50c3Schristos update_adr(view, immed);
5418ed0d50c3Schristos // Check -2^32 <= X < 2^32
5419ed0d50c3Schristos return (size == 64 && Bits<33>::has_overflow((x))
5420ed0d50c3Schristos ? This::STATUS_OVERFLOW
5421ed0d50c3Schristos : This::STATUS_OKAY);
5422ed0d50c3Schristos }
5423ed0d50c3Schristos
5424ed0d50c3Schristos // Calculate PG(S+A) - PG(address), update adrp instruction.
5425ed0d50c3Schristos // R_AARCH64_ADR_PREL_PG_HI21
5426ed0d50c3Schristos
5427ed0d50c3Schristos static inline typename This::Status
adrp(unsigned char * view,const Sized_relobj_file<size,big_endian> * object,const Symbol_value<size> * psymval,Address addend,Address address,const AArch64_reloc_property * reloc_property)5428ed0d50c3Schristos adrp(unsigned char* view,
5429ed0d50c3Schristos const Sized_relobj_file<size, big_endian>* object,
5430ed0d50c3Schristos const Symbol_value<size>* psymval,
5431ed0d50c3Schristos Address addend,
5432ed0d50c3Schristos Address address,
5433ed0d50c3Schristos const AArch64_reloc_property* reloc_property)
5434ed0d50c3Schristos {
5435ed0d50c3Schristos Address sa = psymval->value(object, addend);
5436ed0d50c3Schristos AArch64_valtype x = This::Page(sa) - This::Page(address);
5437ed0d50c3Schristos // Pick [32:12] of X.
5438ed0d50c3Schristos AArch64_valtype immed = (x >> 12) & 0x1fffff;
5439ed0d50c3Schristos update_adr(view, immed);
5440ed0d50c3Schristos return (reloc_property->checkup_x_value(x)
5441ed0d50c3Schristos ? This::STATUS_OKAY
5442ed0d50c3Schristos : This::STATUS_OVERFLOW);
5443ed0d50c3Schristos }
5444ed0d50c3Schristos
5445ed0d50c3Schristos // Update mov[n/z] instruction. Check overflow if needed.
5446ed0d50c3Schristos // If X >=0, set the instruction to movz and its immediate value to the
5447ed0d50c3Schristos // selected bits S.
5448ed0d50c3Schristos // If X < 0, set the instruction to movn and its immediate value to
5449ed0d50c3Schristos // NOT (selected bits of).
5450ed0d50c3Schristos
5451ed0d50c3Schristos static inline typename This::Status
movnz(unsigned char * view,AArch64_valtype x,const AArch64_reloc_property * reloc_property)5452ed0d50c3Schristos movnz(unsigned char* view,
5453ed0d50c3Schristos AArch64_valtype x,
5454ed0d50c3Schristos const AArch64_reloc_property* reloc_property)
5455ed0d50c3Schristos {
5456ed0d50c3Schristos // Select bits from X.
5457ed0d50c3Schristos Address immed;
5458ed0d50c3Schristos bool is_movz;
5459ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Swxword SignedW;
5460ed0d50c3Schristos if (static_cast<SignedW>(x) >= 0)
5461ed0d50c3Schristos {
5462ed0d50c3Schristos immed = reloc_property->select_x_value(x);
5463ed0d50c3Schristos is_movz = true;
5464ed0d50c3Schristos }
5465ed0d50c3Schristos else
5466ed0d50c3Schristos {
5467ed0d50c3Schristos immed = reloc_property->select_x_value(~x);;
5468ed0d50c3Schristos is_movz = false;
5469ed0d50c3Schristos }
5470ed0d50c3Schristos
5471ed0d50c3Schristos // Update movnz instruction.
5472ed0d50c3Schristos update_movnz(view, immed, is_movz);
5473ed0d50c3Schristos
5474ed0d50c3Schristos // Do check overflow or alignment if needed.
5475ed0d50c3Schristos return (reloc_property->checkup_x_value(x)
5476ed0d50c3Schristos ? This::STATUS_OKAY
5477ed0d50c3Schristos : This::STATUS_OVERFLOW);
5478ed0d50c3Schristos }
5479ed0d50c3Schristos
5480ed0d50c3Schristos static inline bool
5481ed0d50c3Schristos maybe_apply_stub(unsigned int,
5482ed0d50c3Schristos const The_relocate_info*,
5483ed0d50c3Schristos const The_rela&,
5484ed0d50c3Schristos unsigned char*,
5485ed0d50c3Schristos Address,
5486ed0d50c3Schristos const Sized_symbol<size>*,
5487ed0d50c3Schristos const Symbol_value<size>*,
5488ed0d50c3Schristos const Sized_relobj_file<size, big_endian>*,
5489ed0d50c3Schristos section_size_type);
5490ed0d50c3Schristos
5491ed0d50c3Schristos }; // End of AArch64_relocate_functions
5492ed0d50c3Schristos
5493ed0d50c3Schristos
5494ed0d50c3Schristos // For a certain relocation type (usually jump/branch), test to see if the
5495ed0d50c3Schristos // destination needs a stub to fulfil. If so, re-route the destination of the
5496ed0d50c3Schristos // original instruction to the stub, note, at this time, the stub has already
5497ed0d50c3Schristos // been generated.
5498ed0d50c3Schristos
5499ed0d50c3Schristos template<int size, bool big_endian>
5500ed0d50c3Schristos bool
5501ed0d50c3Schristos AArch64_relocate_functions<size, big_endian>::
maybe_apply_stub(unsigned int r_type,const The_relocate_info * relinfo,const The_rela & rela,unsigned char * view,Address address,const Sized_symbol<size> * gsym,const Symbol_value<size> * psymval,const Sized_relobj_file<size,big_endian> * object,section_size_type current_group_size)5502ed0d50c3Schristos maybe_apply_stub(unsigned int r_type,
5503ed0d50c3Schristos const The_relocate_info* relinfo,
5504ed0d50c3Schristos const The_rela& rela,
5505ed0d50c3Schristos unsigned char* view,
5506ed0d50c3Schristos Address address,
5507ed0d50c3Schristos const Sized_symbol<size>* gsym,
5508ed0d50c3Schristos const Symbol_value<size>* psymval,
5509ed0d50c3Schristos const Sized_relobj_file<size, big_endian>* object,
5510ed0d50c3Schristos section_size_type current_group_size)
5511ed0d50c3Schristos {
5512ed0d50c3Schristos if (parameters->options().relocatable())
5513ed0d50c3Schristos return false;
5514ed0d50c3Schristos
5515ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Swxword addend = rela.get_r_addend();
5516ed0d50c3Schristos Address branch_target = psymval->value(object, 0) + addend;
5517ed0d50c3Schristos int stub_type =
5518ed0d50c3Schristos The_reloc_stub::stub_type_for_reloc(r_type, address, branch_target);
5519ed0d50c3Schristos if (stub_type == ST_NONE)
5520ed0d50c3Schristos return false;
5521ed0d50c3Schristos
5522ed0d50c3Schristos const The_aarch64_relobj* aarch64_relobj =
5523ed0d50c3Schristos static_cast<const The_aarch64_relobj*>(object);
552406324dcfSchristos const AArch64_reloc_property* arp =
552506324dcfSchristos aarch64_reloc_property_table->get_reloc_property(r_type);
552606324dcfSchristos gold_assert(arp != NULL);
552706324dcfSchristos
552806324dcfSchristos // We don't create stubs for undefined symbols, but do for weak.
552906324dcfSchristos if (gsym
553006324dcfSchristos && !gsym->use_plt_offset(arp->reference_flags())
553106324dcfSchristos && gsym->is_undefined())
553206324dcfSchristos {
553306324dcfSchristos gold_debug(DEBUG_TARGET,
553406324dcfSchristos "stub: looking for a stub for undefined symbol %s in file %s",
553506324dcfSchristos gsym->name(), aarch64_relobj->name().c_str());
553606324dcfSchristos return false;
553706324dcfSchristos }
553806324dcfSchristos
5539ed0d50c3Schristos The_stub_table* stub_table = aarch64_relobj->stub_table(relinfo->data_shndx);
5540ed0d50c3Schristos gold_assert(stub_table != NULL);
5541ed0d50c3Schristos
5542ed0d50c3Schristos unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
5543ed0d50c3Schristos typename The_reloc_stub::Key stub_key(stub_type, gsym, object, r_sym, addend);
5544ed0d50c3Schristos The_reloc_stub* stub = stub_table->find_reloc_stub(stub_key);
5545ed0d50c3Schristos gold_assert(stub != NULL);
5546ed0d50c3Schristos
5547ed0d50c3Schristos Address new_branch_target = stub_table->address() + stub->offset();
5548ed0d50c3Schristos typename elfcpp::Swap<size, big_endian>::Valtype branch_offset =
5549ed0d50c3Schristos new_branch_target - address;
5550ed0d50c3Schristos typename This::Status status = This::template
5551ed0d50c3Schristos rela_general<32>(view, branch_offset, 0, arp);
5552ed0d50c3Schristos if (status != This::STATUS_OKAY)
5553ed0d50c3Schristos gold_error(_("Stub is too far away, try a smaller value "
5554ed0d50c3Schristos "for '--stub-group-size'. The current value is 0x%lx."),
5555ed0d50c3Schristos static_cast<unsigned long>(current_group_size));
5556ed0d50c3Schristos return true;
5557ed0d50c3Schristos }
5558ed0d50c3Schristos
5559ed0d50c3Schristos
5560ed0d50c3Schristos // Group input sections for stub generation.
5561ed0d50c3Schristos //
5562ed0d50c3Schristos // We group input sections in an output section so that the total size,
5563ed0d50c3Schristos // including any padding space due to alignment is smaller than GROUP_SIZE
5564ed0d50c3Schristos // unless the only input section in group is bigger than GROUP_SIZE already.
5565ed0d50c3Schristos // Then an ARM stub table is created to follow the last input section
5566ed0d50c3Schristos // in group. For each group an ARM stub table is created an is placed
5567ed0d50c3Schristos // after the last group. If STUB_ALWAYS_AFTER_BRANCH is false, we further
5568ed0d50c3Schristos // extend the group after the stub table.
5569ed0d50c3Schristos
5570ed0d50c3Schristos template<int size, bool big_endian>
5571ed0d50c3Schristos void
group_sections(Layout * layout,section_size_type group_size,bool stubs_always_after_branch,const Task * task)5572ed0d50c3Schristos Target_aarch64<size, big_endian>::group_sections(
5573ed0d50c3Schristos Layout* layout,
5574ed0d50c3Schristos section_size_type group_size,
5575ed0d50c3Schristos bool stubs_always_after_branch,
5576ed0d50c3Schristos const Task* task)
5577ed0d50c3Schristos {
5578ed0d50c3Schristos // Group input sections and insert stub table
5579ed0d50c3Schristos Layout::Section_list section_list;
5580ed0d50c3Schristos layout->get_executable_sections(§ion_list);
5581ed0d50c3Schristos for (Layout::Section_list::const_iterator p = section_list.begin();
5582ed0d50c3Schristos p != section_list.end();
5583ed0d50c3Schristos ++p)
5584ed0d50c3Schristos {
5585ed0d50c3Schristos AArch64_output_section<size, big_endian>* output_section =
5586ed0d50c3Schristos static_cast<AArch64_output_section<size, big_endian>*>(*p);
5587ed0d50c3Schristos output_section->group_sections(group_size, stubs_always_after_branch,
5588ed0d50c3Schristos this, task);
5589ed0d50c3Schristos }
5590ed0d50c3Schristos }
5591ed0d50c3Schristos
5592ed0d50c3Schristos
5593ed0d50c3Schristos // Find the AArch64_input_section object corresponding to the SHNDX-th input
5594ed0d50c3Schristos // section of RELOBJ.
5595ed0d50c3Schristos
5596ed0d50c3Schristos template<int size, bool big_endian>
5597ed0d50c3Schristos AArch64_input_section<size, big_endian>*
find_aarch64_input_section(Relobj * relobj,unsigned int shndx) const5598ed0d50c3Schristos Target_aarch64<size, big_endian>::find_aarch64_input_section(
5599ed0d50c3Schristos Relobj* relobj, unsigned int shndx) const
5600ed0d50c3Schristos {
5601ed0d50c3Schristos Section_id sid(relobj, shndx);
5602ed0d50c3Schristos typename AArch64_input_section_map::const_iterator p =
5603ed0d50c3Schristos this->aarch64_input_section_map_.find(sid);
5604ed0d50c3Schristos return (p != this->aarch64_input_section_map_.end()) ? p->second : NULL;
5605ed0d50c3Schristos }
5606ed0d50c3Schristos
5607ed0d50c3Schristos
5608ed0d50c3Schristos // Make a new AArch64_input_section object.
5609ed0d50c3Schristos
5610ed0d50c3Schristos template<int size, bool big_endian>
5611ed0d50c3Schristos AArch64_input_section<size, big_endian>*
new_aarch64_input_section(Relobj * relobj,unsigned int shndx)5612ed0d50c3Schristos Target_aarch64<size, big_endian>::new_aarch64_input_section(
5613ed0d50c3Schristos Relobj* relobj, unsigned int shndx)
5614ed0d50c3Schristos {
5615ed0d50c3Schristos Section_id sid(relobj, shndx);
5616ed0d50c3Schristos
5617ed0d50c3Schristos AArch64_input_section<size, big_endian>* input_section =
5618ed0d50c3Schristos new AArch64_input_section<size, big_endian>(relobj, shndx);
5619ed0d50c3Schristos input_section->init();
5620ed0d50c3Schristos
5621ed0d50c3Schristos // Register new AArch64_input_section in map for look-up.
5622ed0d50c3Schristos std::pair<typename AArch64_input_section_map::iterator,bool> ins =
5623ed0d50c3Schristos this->aarch64_input_section_map_.insert(
5624ed0d50c3Schristos std::make_pair(sid, input_section));
5625ed0d50c3Schristos
5626ed0d50c3Schristos // Make sure that it we have not created another AArch64_input_section
5627ed0d50c3Schristos // for this input section already.
5628ed0d50c3Schristos gold_assert(ins.second);
5629ed0d50c3Schristos
5630ed0d50c3Schristos return input_section;
5631ed0d50c3Schristos }
5632ed0d50c3Schristos
5633ed0d50c3Schristos
5634ed0d50c3Schristos // Relaxation hook. This is where we do stub generation.
5635ed0d50c3Schristos
5636ed0d50c3Schristos template<int size, bool big_endian>
5637ed0d50c3Schristos bool
do_relax(int pass,const Input_objects * input_objects,Symbol_table * symtab,Layout * layout,const Task * task)5638ed0d50c3Schristos Target_aarch64<size, big_endian>::do_relax(
5639ed0d50c3Schristos int pass,
5640ed0d50c3Schristos const Input_objects* input_objects,
5641ed0d50c3Schristos Symbol_table* symtab,
5642ed0d50c3Schristos Layout* layout ,
5643ed0d50c3Schristos const Task* task)
5644ed0d50c3Schristos {
5645ed0d50c3Schristos gold_assert(!parameters->options().relocatable());
5646ed0d50c3Schristos if (pass == 1)
5647ed0d50c3Schristos {
5648ed0d50c3Schristos // We don't handle negative stub_group_size right now.
5649ed0d50c3Schristos this->stub_group_size_ = abs(parameters->options().stub_group_size());
5650ed0d50c3Schristos if (this->stub_group_size_ == 1)
5651ed0d50c3Schristos {
5652ed0d50c3Schristos // Leave room for 4096 4-byte stub entries. If we exceed that, then we
5653ed0d50c3Schristos // will fail to link. The user will have to relink with an explicit
5654ed0d50c3Schristos // group size option.
5655ed0d50c3Schristos this->stub_group_size_ = The_reloc_stub::MAX_BRANCH_OFFSET -
5656ed0d50c3Schristos 4096 * 4;
5657ed0d50c3Schristos }
5658ed0d50c3Schristos group_sections(layout, this->stub_group_size_, true, task);
5659ed0d50c3Schristos }
5660ed0d50c3Schristos else
5661ed0d50c3Schristos {
5662ed0d50c3Schristos // If this is not the first pass, addresses and file offsets have
5663ed0d50c3Schristos // been reset at this point, set them here.
5664ed0d50c3Schristos for (Stub_table_iterator sp = this->stub_tables_.begin();
5665ed0d50c3Schristos sp != this->stub_tables_.end(); ++sp)
5666ed0d50c3Schristos {
5667ed0d50c3Schristos The_stub_table* stt = *sp;
5668ed0d50c3Schristos The_aarch64_input_section* owner = stt->owner();
5669ed0d50c3Schristos off_t off = align_address(owner->original_size(),
5670ed0d50c3Schristos stt->addralign());
5671ed0d50c3Schristos stt->set_address_and_file_offset(owner->address() + off,
5672ed0d50c3Schristos owner->offset() + off);
5673ed0d50c3Schristos }
5674ed0d50c3Schristos }
5675ed0d50c3Schristos
5676ed0d50c3Schristos // Scan relocs for relocation stubs
5677ed0d50c3Schristos for (Input_objects::Relobj_iterator op = input_objects->relobj_begin();
5678ed0d50c3Schristos op != input_objects->relobj_end();
5679ed0d50c3Schristos ++op)
5680ed0d50c3Schristos {
5681ed0d50c3Schristos The_aarch64_relobj* aarch64_relobj =
5682ed0d50c3Schristos static_cast<The_aarch64_relobj*>(*op);
5683ed0d50c3Schristos // Lock the object so we can read from it. This is only called
5684ed0d50c3Schristos // single-threaded from Layout::finalize, so it is OK to lock.
5685ed0d50c3Schristos Task_lock_obj<Object> tl(task, aarch64_relobj);
5686ed0d50c3Schristos aarch64_relobj->scan_sections_for_stubs(this, symtab, layout);
5687ed0d50c3Schristos }
5688ed0d50c3Schristos
5689ed0d50c3Schristos bool any_stub_table_changed = false;
5690ed0d50c3Schristos for (Stub_table_iterator siter = this->stub_tables_.begin();
5691ed0d50c3Schristos siter != this->stub_tables_.end() && !any_stub_table_changed; ++siter)
5692ed0d50c3Schristos {
5693ed0d50c3Schristos The_stub_table* stub_table = *siter;
5694ed0d50c3Schristos if (stub_table->update_data_size_changed_p())
5695ed0d50c3Schristos {
5696ed0d50c3Schristos The_aarch64_input_section* owner = stub_table->owner();
5697ed0d50c3Schristos uint64_t address = owner->address();
5698ed0d50c3Schristos off_t offset = owner->offset();
5699ed0d50c3Schristos owner->reset_address_and_file_offset();
5700ed0d50c3Schristos owner->set_address_and_file_offset(address, offset);
5701ed0d50c3Schristos
5702ed0d50c3Schristos any_stub_table_changed = true;
5703ed0d50c3Schristos }
5704ed0d50c3Schristos }
5705ed0d50c3Schristos
5706ed0d50c3Schristos // Do not continue relaxation.
5707ed0d50c3Schristos bool continue_relaxation = any_stub_table_changed;
5708ed0d50c3Schristos if (!continue_relaxation)
5709ed0d50c3Schristos for (Stub_table_iterator sp = this->stub_tables_.begin();
5710ed0d50c3Schristos (sp != this->stub_tables_.end());
5711ed0d50c3Schristos ++sp)
5712ed0d50c3Schristos (*sp)->finalize_stubs();
5713ed0d50c3Schristos
5714ed0d50c3Schristos return continue_relaxation;
5715ed0d50c3Schristos }
5716ed0d50c3Schristos
5717ed0d50c3Schristos
5718ed0d50c3Schristos // Make a new Stub_table.
5719ed0d50c3Schristos
5720ed0d50c3Schristos template<int size, bool big_endian>
5721ed0d50c3Schristos Stub_table<size, big_endian>*
new_stub_table(AArch64_input_section<size,big_endian> * owner)5722ed0d50c3Schristos Target_aarch64<size, big_endian>::new_stub_table(
5723ed0d50c3Schristos AArch64_input_section<size, big_endian>* owner)
5724ed0d50c3Schristos {
5725ed0d50c3Schristos Stub_table<size, big_endian>* stub_table =
5726ed0d50c3Schristos new Stub_table<size, big_endian>(owner);
5727ed0d50c3Schristos stub_table->set_address(align_address(
5728ed0d50c3Schristos owner->address() + owner->data_size(), 8));
5729ed0d50c3Schristos stub_table->set_file_offset(owner->offset() + owner->data_size());
5730ed0d50c3Schristos stub_table->finalize_data_size();
5731ed0d50c3Schristos
5732ed0d50c3Schristos this->stub_tables_.push_back(stub_table);
5733ed0d50c3Schristos
5734ed0d50c3Schristos return stub_table;
5735ed0d50c3Schristos }
5736ed0d50c3Schristos
5737ed0d50c3Schristos
5738ed0d50c3Schristos template<int size, bool big_endian>
5739ed0d50c3Schristos uint64_t
do_reloc_addend(void * arg,unsigned int r_type,uint64_t) const5740ed0d50c3Schristos Target_aarch64<size, big_endian>::do_reloc_addend(
5741ed0d50c3Schristos void* arg, unsigned int r_type, uint64_t) const
5742ed0d50c3Schristos {
5743ed0d50c3Schristos gold_assert(r_type == elfcpp::R_AARCH64_TLSDESC);
5744ed0d50c3Schristos uintptr_t intarg = reinterpret_cast<uintptr_t>(arg);
5745ed0d50c3Schristos gold_assert(intarg < this->tlsdesc_reloc_info_.size());
5746ed0d50c3Schristos const Tlsdesc_info& ti(this->tlsdesc_reloc_info_[intarg]);
5747ed0d50c3Schristos const Symbol_value<size>* psymval = ti.object->local_symbol(ti.r_sym);
5748ed0d50c3Schristos gold_assert(psymval->is_tls_symbol());
5749ed0d50c3Schristos // The value of a TLS symbol is the offset in the TLS segment.
5750ed0d50c3Schristos return psymval->value(ti.object, 0);
5751ed0d50c3Schristos }
5752ed0d50c3Schristos
5753ed0d50c3Schristos // Return the number of entries in the PLT.
5754ed0d50c3Schristos
5755ed0d50c3Schristos template<int size, bool big_endian>
5756ed0d50c3Schristos unsigned int
plt_entry_count() const5757ed0d50c3Schristos Target_aarch64<size, big_endian>::plt_entry_count() const
5758ed0d50c3Schristos {
5759ed0d50c3Schristos if (this->plt_ == NULL)
5760ed0d50c3Schristos return 0;
5761ed0d50c3Schristos return this->plt_->entry_count();
5762ed0d50c3Schristos }
5763ed0d50c3Schristos
5764ed0d50c3Schristos // Return the offset of the first non-reserved PLT entry.
5765ed0d50c3Schristos
5766ed0d50c3Schristos template<int size, bool big_endian>
5767ed0d50c3Schristos unsigned int
first_plt_entry_offset() const5768ed0d50c3Schristos Target_aarch64<size, big_endian>::first_plt_entry_offset() const
5769ed0d50c3Schristos {
5770ed0d50c3Schristos return this->plt_->first_plt_entry_offset();
5771ed0d50c3Schristos }
5772ed0d50c3Schristos
5773ed0d50c3Schristos // Return the size of each PLT entry.
5774ed0d50c3Schristos
5775ed0d50c3Schristos template<int size, bool big_endian>
5776ed0d50c3Schristos unsigned int
plt_entry_size() const5777ed0d50c3Schristos Target_aarch64<size, big_endian>::plt_entry_size() const
5778ed0d50c3Schristos {
5779ed0d50c3Schristos return this->plt_->get_plt_entry_size();
5780ed0d50c3Schristos }
5781ed0d50c3Schristos
5782ed0d50c3Schristos // Define the _TLS_MODULE_BASE_ symbol in the TLS segment.
5783ed0d50c3Schristos
5784ed0d50c3Schristos template<int size, bool big_endian>
5785ed0d50c3Schristos void
define_tls_base_symbol(Symbol_table * symtab,Layout * layout)5786ed0d50c3Schristos Target_aarch64<size, big_endian>::define_tls_base_symbol(
5787ed0d50c3Schristos Symbol_table* symtab, Layout* layout)
5788ed0d50c3Schristos {
5789ed0d50c3Schristos if (this->tls_base_symbol_defined_)
5790ed0d50c3Schristos return;
5791ed0d50c3Schristos
5792ed0d50c3Schristos Output_segment* tls_segment = layout->tls_segment();
5793ed0d50c3Schristos if (tls_segment != NULL)
5794ed0d50c3Schristos {
5795ed0d50c3Schristos // _TLS_MODULE_BASE_ always points to the beginning of tls segment.
5796ed0d50c3Schristos symtab->define_in_output_segment("_TLS_MODULE_BASE_", NULL,
5797ed0d50c3Schristos Symbol_table::PREDEFINED,
5798ed0d50c3Schristos tls_segment, 0, 0,
5799ed0d50c3Schristos elfcpp::STT_TLS,
5800ed0d50c3Schristos elfcpp::STB_LOCAL,
5801ed0d50c3Schristos elfcpp::STV_HIDDEN, 0,
5802ed0d50c3Schristos Symbol::SEGMENT_START,
5803ed0d50c3Schristos true);
5804ed0d50c3Schristos }
5805ed0d50c3Schristos this->tls_base_symbol_defined_ = true;
5806ed0d50c3Schristos }
5807ed0d50c3Schristos
5808ed0d50c3Schristos // Create the reserved PLT and GOT entries for the TLS descriptor resolver.
5809ed0d50c3Schristos
5810ed0d50c3Schristos template<int size, bool big_endian>
5811ed0d50c3Schristos void
reserve_tlsdesc_entries(Symbol_table * symtab,Layout * layout)5812ed0d50c3Schristos Target_aarch64<size, big_endian>::reserve_tlsdesc_entries(
5813ed0d50c3Schristos Symbol_table* symtab, Layout* layout)
5814ed0d50c3Schristos {
5815ed0d50c3Schristos if (this->plt_ == NULL)
5816ed0d50c3Schristos this->make_plt_section(symtab, layout);
5817ed0d50c3Schristos
5818ed0d50c3Schristos if (!this->plt_->has_tlsdesc_entry())
5819ed0d50c3Schristos {
5820ed0d50c3Schristos // Allocate the TLSDESC_GOT entry.
5821ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>* got =
5822ed0d50c3Schristos this->got_section(symtab, layout);
5823ed0d50c3Schristos unsigned int got_offset = got->add_constant(0);
5824ed0d50c3Schristos
5825ed0d50c3Schristos // Allocate the TLSDESC_PLT entry.
5826ed0d50c3Schristos this->plt_->reserve_tlsdesc_entry(got_offset);
5827ed0d50c3Schristos }
5828ed0d50c3Schristos }
5829ed0d50c3Schristos
5830ed0d50c3Schristos // Create a GOT entry for the TLS module index.
5831ed0d50c3Schristos
5832ed0d50c3Schristos template<int size, bool big_endian>
5833ed0d50c3Schristos unsigned int
got_mod_index_entry(Symbol_table * symtab,Layout * layout,Sized_relobj_file<size,big_endian> * object)5834ed0d50c3Schristos Target_aarch64<size, big_endian>::got_mod_index_entry(
5835ed0d50c3Schristos Symbol_table* symtab, Layout* layout,
5836ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object)
5837ed0d50c3Schristos {
5838ed0d50c3Schristos if (this->got_mod_index_offset_ == -1U)
5839ed0d50c3Schristos {
5840ed0d50c3Schristos gold_assert(symtab != NULL && layout != NULL && object != NULL);
5841ed0d50c3Schristos Reloc_section* rela_dyn = this->rela_dyn_section(layout);
5842ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>* got =
5843ed0d50c3Schristos this->got_section(symtab, layout);
5844ed0d50c3Schristos unsigned int got_offset = got->add_constant(0);
5845ed0d50c3Schristos rela_dyn->add_local(object, 0, elfcpp::R_AARCH64_TLS_DTPMOD64, got,
5846ed0d50c3Schristos got_offset, 0);
5847ed0d50c3Schristos got->add_constant(0);
5848ed0d50c3Schristos this->got_mod_index_offset_ = got_offset;
5849ed0d50c3Schristos }
5850ed0d50c3Schristos return this->got_mod_index_offset_;
5851ed0d50c3Schristos }
5852ed0d50c3Schristos
5853ed0d50c3Schristos // Optimize the TLS relocation type based on what we know about the
5854ed0d50c3Schristos // symbol. IS_FINAL is true if the final address of this symbol is
5855ed0d50c3Schristos // known at link time.
5856ed0d50c3Schristos
5857ed0d50c3Schristos template<int size, bool big_endian>
5858ed0d50c3Schristos tls::Tls_optimization
optimize_tls_reloc(bool is_final,int r_type)5859ed0d50c3Schristos Target_aarch64<size, big_endian>::optimize_tls_reloc(bool is_final,
5860ed0d50c3Schristos int r_type)
5861ed0d50c3Schristos {
5862ed0d50c3Schristos // If we are generating a shared library, then we can't do anything
5863ed0d50c3Schristos // in the linker
5864ed0d50c3Schristos if (parameters->options().shared())
5865ed0d50c3Schristos return tls::TLSOPT_NONE;
5866ed0d50c3Schristos
5867ed0d50c3Schristos switch (r_type)
5868ed0d50c3Schristos {
5869ed0d50c3Schristos case elfcpp::R_AARCH64_TLSGD_ADR_PAGE21:
5870ed0d50c3Schristos case elfcpp::R_AARCH64_TLSGD_ADD_LO12_NC:
5871ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_LD_PREL19:
5872ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADR_PREL21:
5873ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADR_PAGE21:
5874ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_LD64_LO12:
5875ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADD_LO12:
5876ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_OFF_G1:
5877ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_OFF_G0_NC:
5878ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_LDR:
5879ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADD:
5880ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_CALL:
5881ed0d50c3Schristos // These are General-Dynamic which permits fully general TLS
5882ed0d50c3Schristos // access. Since we know that we are generating an executable,
5883ed0d50c3Schristos // we can convert this to Initial-Exec. If we also know that
5884ed0d50c3Schristos // this is a local symbol, we can further switch to Local-Exec.
5885ed0d50c3Schristos if (is_final)
5886ed0d50c3Schristos return tls::TLSOPT_TO_LE;
5887ed0d50c3Schristos return tls::TLSOPT_TO_IE;
5888ed0d50c3Schristos
5889ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADR_PAGE21:
5890ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_LO12_NC:
5891ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G1:
5892ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC:
5893ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_HI12:
5894ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC:
5895ed0d50c3Schristos // These are Local-Dynamic, which refer to local symbols in the
5896ed0d50c3Schristos // dynamic TLS block. Since we know that we generating an
5897ed0d50c3Schristos // executable, we can switch to Local-Exec.
5898ed0d50c3Schristos return tls::TLSOPT_TO_LE;
5899ed0d50c3Schristos
5900ed0d50c3Schristos case elfcpp::R_AARCH64_TLSIE_MOVW_GOTTPREL_G1:
5901ed0d50c3Schristos case elfcpp::R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC:
5902ed0d50c3Schristos case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
5903ed0d50c3Schristos case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
5904ed0d50c3Schristos case elfcpp::R_AARCH64_TLSIE_LD_GOTTPREL_PREL19:
5905ed0d50c3Schristos // These are Initial-Exec relocs which get the thread offset
5906ed0d50c3Schristos // from the GOT. If we know that we are linking against the
5907ed0d50c3Schristos // local symbol, we can switch to Local-Exec, which links the
5908ed0d50c3Schristos // thread offset into the instruction.
5909ed0d50c3Schristos if (is_final)
5910ed0d50c3Schristos return tls::TLSOPT_TO_LE;
5911ed0d50c3Schristos return tls::TLSOPT_NONE;
5912ed0d50c3Schristos
5913ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G2:
5914ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G1:
5915ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
5916ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G0:
5917ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
5918ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12:
5919ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12:
5920ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
592106324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12:
592206324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
592306324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12:
592406324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
592506324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12:
592606324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
592706324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12:
592806324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
5929ed0d50c3Schristos // When we already have Local-Exec, there is nothing further we
5930ed0d50c3Schristos // can do.
5931ed0d50c3Schristos return tls::TLSOPT_NONE;
5932ed0d50c3Schristos
5933ed0d50c3Schristos default:
5934ed0d50c3Schristos gold_unreachable();
5935ed0d50c3Schristos }
5936ed0d50c3Schristos }
5937ed0d50c3Schristos
5938ed0d50c3Schristos // Returns true if this relocation type could be that of a function pointer.
5939ed0d50c3Schristos
5940ed0d50c3Schristos template<int size, bool big_endian>
5941ed0d50c3Schristos inline bool
possible_function_pointer_reloc(unsigned int r_type)5942ed0d50c3Schristos Target_aarch64<size, big_endian>::Scan::possible_function_pointer_reloc(
5943ed0d50c3Schristos unsigned int r_type)
5944ed0d50c3Schristos {
5945ed0d50c3Schristos switch (r_type)
5946ed0d50c3Schristos {
5947ed0d50c3Schristos case elfcpp::R_AARCH64_ADR_PREL_PG_HI21:
5948ed0d50c3Schristos case elfcpp::R_AARCH64_ADR_PREL_PG_HI21_NC:
5949ed0d50c3Schristos case elfcpp::R_AARCH64_ADD_ABS_LO12_NC:
5950ed0d50c3Schristos case elfcpp::R_AARCH64_ADR_GOT_PAGE:
5951ed0d50c3Schristos case elfcpp::R_AARCH64_LD64_GOT_LO12_NC:
5952ed0d50c3Schristos {
5953ed0d50c3Schristos return true;
5954ed0d50c3Schristos }
5955ed0d50c3Schristos }
5956ed0d50c3Schristos return false;
5957ed0d50c3Schristos }
5958ed0d50c3Schristos
5959ed0d50c3Schristos // For safe ICF, scan a relocation for a local symbol to check if it
5960ed0d50c3Schristos // corresponds to a function pointer being taken. In that case mark
5961ed0d50c3Schristos // the function whose pointer was taken as not foldable.
5962ed0d50c3Schristos
5963ed0d50c3Schristos template<int size, bool big_endian>
5964ed0d50c3Schristos inline bool
local_reloc_may_be_function_pointer(Symbol_table *,Layout *,Target_aarch64<size,big_endian> *,Sized_relobj_file<size,big_endian> *,unsigned int,Output_section *,const elfcpp::Rela<size,big_endian> &,unsigned int r_type,const elfcpp::Sym<size,big_endian> &)5965ed0d50c3Schristos Target_aarch64<size, big_endian>::Scan::local_reloc_may_be_function_pointer(
5966ed0d50c3Schristos Symbol_table* ,
5967ed0d50c3Schristos Layout* ,
5968ed0d50c3Schristos Target_aarch64<size, big_endian>* ,
5969ed0d50c3Schristos Sized_relobj_file<size, big_endian>* ,
5970ed0d50c3Schristos unsigned int ,
5971ed0d50c3Schristos Output_section* ,
5972ed0d50c3Schristos const elfcpp::Rela<size, big_endian>& ,
5973ed0d50c3Schristos unsigned int r_type,
5974ed0d50c3Schristos const elfcpp::Sym<size, big_endian>&)
5975ed0d50c3Schristos {
5976ed0d50c3Schristos // When building a shared library, do not fold any local symbols.
5977ed0d50c3Schristos return (parameters->options().shared()
5978ed0d50c3Schristos || possible_function_pointer_reloc(r_type));
5979ed0d50c3Schristos }
5980ed0d50c3Schristos
5981ed0d50c3Schristos // For safe ICF, scan a relocation for a global symbol to check if it
5982ed0d50c3Schristos // corresponds to a function pointer being taken. In that case mark
5983ed0d50c3Schristos // the function whose pointer was taken as not foldable.
5984ed0d50c3Schristos
5985ed0d50c3Schristos template<int size, bool big_endian>
5986ed0d50c3Schristos inline bool
global_reloc_may_be_function_pointer(Symbol_table *,Layout *,Target_aarch64<size,big_endian> *,Sized_relobj_file<size,big_endian> *,unsigned int,Output_section *,const elfcpp::Rela<size,big_endian> &,unsigned int r_type,Symbol * gsym)5987ed0d50c3Schristos Target_aarch64<size, big_endian>::Scan::global_reloc_may_be_function_pointer(
5988ed0d50c3Schristos Symbol_table* ,
5989ed0d50c3Schristos Layout* ,
5990ed0d50c3Schristos Target_aarch64<size, big_endian>* ,
5991ed0d50c3Schristos Sized_relobj_file<size, big_endian>* ,
5992ed0d50c3Schristos unsigned int ,
5993ed0d50c3Schristos Output_section* ,
5994ed0d50c3Schristos const elfcpp::Rela<size, big_endian>& ,
5995ed0d50c3Schristos unsigned int r_type,
5996ed0d50c3Schristos Symbol* gsym)
5997ed0d50c3Schristos {
5998ed0d50c3Schristos // When building a shared library, do not fold symbols whose visibility
5999ed0d50c3Schristos // is hidden, internal or protected.
6000ed0d50c3Schristos return ((parameters->options().shared()
6001ed0d50c3Schristos && (gsym->visibility() == elfcpp::STV_INTERNAL
6002ed0d50c3Schristos || gsym->visibility() == elfcpp::STV_PROTECTED
6003ed0d50c3Schristos || gsym->visibility() == elfcpp::STV_HIDDEN))
6004ed0d50c3Schristos || possible_function_pointer_reloc(r_type));
6005ed0d50c3Schristos }
6006ed0d50c3Schristos
6007ed0d50c3Schristos // Report an unsupported relocation against a local symbol.
6008ed0d50c3Schristos
6009ed0d50c3Schristos template<int size, bool big_endian>
6010ed0d50c3Schristos void
unsupported_reloc_local(Sized_relobj_file<size,big_endian> * object,unsigned int r_type)6011ed0d50c3Schristos Target_aarch64<size, big_endian>::Scan::unsupported_reloc_local(
6012ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object,
6013ed0d50c3Schristos unsigned int r_type)
6014ed0d50c3Schristos {
6015ed0d50c3Schristos gold_error(_("%s: unsupported reloc %u against local symbol"),
6016ed0d50c3Schristos object->name().c_str(), r_type);
6017ed0d50c3Schristos }
6018ed0d50c3Schristos
6019ed0d50c3Schristos // We are about to emit a dynamic relocation of type R_TYPE. If the
6020ed0d50c3Schristos // dynamic linker does not support it, issue an error.
6021ed0d50c3Schristos
6022ed0d50c3Schristos template<int size, bool big_endian>
6023ed0d50c3Schristos void
check_non_pic(Relobj * object,unsigned int r_type)6024ed0d50c3Schristos Target_aarch64<size, big_endian>::Scan::check_non_pic(Relobj* object,
6025ed0d50c3Schristos unsigned int r_type)
6026ed0d50c3Schristos {
6027ed0d50c3Schristos gold_assert(r_type != elfcpp::R_AARCH64_NONE);
6028ed0d50c3Schristos
6029ed0d50c3Schristos switch (r_type)
6030ed0d50c3Schristos {
6031ed0d50c3Schristos // These are the relocation types supported by glibc for AARCH64.
6032ed0d50c3Schristos case elfcpp::R_AARCH64_NONE:
6033ed0d50c3Schristos case elfcpp::R_AARCH64_COPY:
6034ed0d50c3Schristos case elfcpp::R_AARCH64_GLOB_DAT:
6035ed0d50c3Schristos case elfcpp::R_AARCH64_JUMP_SLOT:
6036ed0d50c3Schristos case elfcpp::R_AARCH64_RELATIVE:
6037ed0d50c3Schristos case elfcpp::R_AARCH64_TLS_DTPREL64:
6038ed0d50c3Schristos case elfcpp::R_AARCH64_TLS_DTPMOD64:
6039ed0d50c3Schristos case elfcpp::R_AARCH64_TLS_TPREL64:
6040ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC:
6041ed0d50c3Schristos case elfcpp::R_AARCH64_IRELATIVE:
6042ed0d50c3Schristos case elfcpp::R_AARCH64_ABS32:
6043ed0d50c3Schristos case elfcpp::R_AARCH64_ABS64:
6044ed0d50c3Schristos return;
6045ed0d50c3Schristos
6046ed0d50c3Schristos default:
6047ed0d50c3Schristos break;
6048ed0d50c3Schristos }
6049ed0d50c3Schristos
6050ed0d50c3Schristos // This prevents us from issuing more than one error per reloc
6051ed0d50c3Schristos // section. But we can still wind up issuing more than one
6052ed0d50c3Schristos // error per object file.
6053ed0d50c3Schristos if (this->issued_non_pic_error_)
6054ed0d50c3Schristos return;
6055ed0d50c3Schristos gold_assert(parameters->options().output_is_position_independent());
6056ed0d50c3Schristos object->error(_("requires unsupported dynamic reloc; "
6057ed0d50c3Schristos "recompile with -fPIC"));
6058ed0d50c3Schristos this->issued_non_pic_error_ = true;
6059ed0d50c3Schristos return;
6060ed0d50c3Schristos }
6061ed0d50c3Schristos
6062ed0d50c3Schristos // Return whether we need to make a PLT entry for a relocation of the
6063ed0d50c3Schristos // given type against a STT_GNU_IFUNC symbol.
6064ed0d50c3Schristos
6065ed0d50c3Schristos template<int size, bool big_endian>
6066ed0d50c3Schristos bool
reloc_needs_plt_for_ifunc(Sized_relobj_file<size,big_endian> * object,unsigned int r_type)6067ed0d50c3Schristos Target_aarch64<size, big_endian>::Scan::reloc_needs_plt_for_ifunc(
6068ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object,
6069ed0d50c3Schristos unsigned int r_type)
6070ed0d50c3Schristos {
6071ed0d50c3Schristos const AArch64_reloc_property* arp =
6072ed0d50c3Schristos aarch64_reloc_property_table->get_reloc_property(r_type);
6073ed0d50c3Schristos gold_assert(arp != NULL);
6074ed0d50c3Schristos
6075ed0d50c3Schristos int flags = arp->reference_flags();
6076ed0d50c3Schristos if (flags & Symbol::TLS_REF)
6077ed0d50c3Schristos {
6078ed0d50c3Schristos gold_error(_("%s: unsupported TLS reloc %s for IFUNC symbol"),
6079ed0d50c3Schristos object->name().c_str(), arp->name().c_str());
6080ed0d50c3Schristos return false;
6081ed0d50c3Schristos }
6082ed0d50c3Schristos return flags != 0;
6083ed0d50c3Schristos }
6084ed0d50c3Schristos
6085ed0d50c3Schristos // Scan a relocation for a local symbol.
6086ed0d50c3Schristos
6087ed0d50c3Schristos template<int size, bool big_endian>
6088ed0d50c3Schristos inline void
local(Symbol_table * symtab,Layout * layout,Target_aarch64<size,big_endian> * target,Sized_relobj_file<size,big_endian> * object,unsigned int data_shndx,Output_section * output_section,const elfcpp::Rela<size,big_endian> & rela,unsigned int r_type,const elfcpp::Sym<size,big_endian> & lsym,bool is_discarded)6089ed0d50c3Schristos Target_aarch64<size, big_endian>::Scan::local(
6090ed0d50c3Schristos Symbol_table* symtab,
6091ed0d50c3Schristos Layout* layout,
6092ed0d50c3Schristos Target_aarch64<size, big_endian>* target,
6093ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object,
6094ed0d50c3Schristos unsigned int data_shndx,
6095ed0d50c3Schristos Output_section* output_section,
6096ed0d50c3Schristos const elfcpp::Rela<size, big_endian>& rela,
6097ed0d50c3Schristos unsigned int r_type,
6098ed0d50c3Schristos const elfcpp::Sym<size, big_endian>& lsym,
6099ed0d50c3Schristos bool is_discarded)
6100ed0d50c3Schristos {
6101ed0d50c3Schristos if (is_discarded)
6102ed0d50c3Schristos return;
6103ed0d50c3Schristos
6104ed0d50c3Schristos typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>
6105ed0d50c3Schristos Reloc_section;
6106ed0d50c3Schristos unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
6107ed0d50c3Schristos
6108ed0d50c3Schristos // A local STT_GNU_IFUNC symbol may require a PLT entry.
6109ed0d50c3Schristos bool is_ifunc = lsym.get_st_type() == elfcpp::STT_GNU_IFUNC;
6110ed0d50c3Schristos if (is_ifunc && this->reloc_needs_plt_for_ifunc(object, r_type))
6111ed0d50c3Schristos target->make_local_ifunc_plt_entry(symtab, layout, object, r_sym);
6112ed0d50c3Schristos
6113ed0d50c3Schristos switch (r_type)
6114ed0d50c3Schristos {
6115ed0d50c3Schristos case elfcpp::R_AARCH64_NONE:
6116ed0d50c3Schristos break;
6117ed0d50c3Schristos
6118ed0d50c3Schristos case elfcpp::R_AARCH64_ABS32:
6119ed0d50c3Schristos case elfcpp::R_AARCH64_ABS16:
6120ed0d50c3Schristos if (parameters->options().output_is_position_independent())
6121ed0d50c3Schristos {
6122ed0d50c3Schristos gold_error(_("%s: unsupported reloc %u in pos independent link."),
6123ed0d50c3Schristos object->name().c_str(), r_type);
6124ed0d50c3Schristos }
6125ed0d50c3Schristos break;
6126ed0d50c3Schristos
6127ed0d50c3Schristos case elfcpp::R_AARCH64_ABS64:
6128ed0d50c3Schristos // If building a shared library or pie, we need to mark this as a dynmic
6129ed0d50c3Schristos // reloction, so that the dynamic loader can relocate it.
6130ed0d50c3Schristos if (parameters->options().output_is_position_independent())
6131ed0d50c3Schristos {
6132ed0d50c3Schristos Reloc_section* rela_dyn = target->rela_dyn_section(layout);
6133ed0d50c3Schristos rela_dyn->add_local_relative(object, r_sym,
6134ed0d50c3Schristos elfcpp::R_AARCH64_RELATIVE,
6135ed0d50c3Schristos output_section,
6136ed0d50c3Schristos data_shndx,
6137ed0d50c3Schristos rela.get_r_offset(),
6138ed0d50c3Schristos rela.get_r_addend(),
6139ed0d50c3Schristos is_ifunc);
6140ed0d50c3Schristos }
6141ed0d50c3Schristos break;
6142ed0d50c3Schristos
6143ed0d50c3Schristos case elfcpp::R_AARCH64_PREL64:
6144ed0d50c3Schristos case elfcpp::R_AARCH64_PREL32:
6145ed0d50c3Schristos case elfcpp::R_AARCH64_PREL16:
6146ed0d50c3Schristos break;
6147ed0d50c3Schristos
6148ed0d50c3Schristos case elfcpp::R_AARCH64_ADR_GOT_PAGE:
6149ed0d50c3Schristos case elfcpp::R_AARCH64_LD64_GOT_LO12_NC:
6150ed0d50c3Schristos case elfcpp::R_AARCH64_LD64_GOTPAGE_LO15:
6151ed0d50c3Schristos // The above relocations are used to access GOT entries.
6152ed0d50c3Schristos {
6153ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>* got =
6154ed0d50c3Schristos target->got_section(symtab, layout);
6155ed0d50c3Schristos bool is_new = false;
6156ed0d50c3Schristos // This symbol requires a GOT entry.
6157ed0d50c3Schristos if (is_ifunc)
6158ed0d50c3Schristos is_new = got->add_local_plt(object, r_sym, GOT_TYPE_STANDARD);
6159ed0d50c3Schristos else
6160ed0d50c3Schristos is_new = got->add_local(object, r_sym, GOT_TYPE_STANDARD);
6161ed0d50c3Schristos if (is_new && parameters->options().output_is_position_independent())
6162ed0d50c3Schristos target->rela_dyn_section(layout)->
6163ed0d50c3Schristos add_local_relative(object,
6164ed0d50c3Schristos r_sym,
6165ed0d50c3Schristos elfcpp::R_AARCH64_RELATIVE,
6166ed0d50c3Schristos got,
6167ed0d50c3Schristos object->local_got_offset(r_sym,
6168ed0d50c3Schristos GOT_TYPE_STANDARD),
6169ed0d50c3Schristos 0,
6170ed0d50c3Schristos false);
6171ed0d50c3Schristos }
6172ed0d50c3Schristos break;
6173ed0d50c3Schristos
617406324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G0: // 263
617506324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G0_NC: // 264
617606324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G1: // 265
617706324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G1_NC: // 266
617806324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G2: // 267
617906324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G2_NC: // 268
618006324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G3: // 269
618106324dcfSchristos case elfcpp::R_AARCH64_MOVW_SABS_G0: // 270
618206324dcfSchristos case elfcpp::R_AARCH64_MOVW_SABS_G1: // 271
618306324dcfSchristos case elfcpp::R_AARCH64_MOVW_SABS_G2: // 272
618406324dcfSchristos if (parameters->options().output_is_position_independent())
618506324dcfSchristos {
618606324dcfSchristos gold_error(_("%s: unsupported reloc %u in pos independent link."),
618706324dcfSchristos object->name().c_str(), r_type);
618806324dcfSchristos }
618906324dcfSchristos break;
619006324dcfSchristos
6191ed0d50c3Schristos case elfcpp::R_AARCH64_LD_PREL_LO19: // 273
6192ed0d50c3Schristos case elfcpp::R_AARCH64_ADR_PREL_LO21: // 274
6193ed0d50c3Schristos case elfcpp::R_AARCH64_ADR_PREL_PG_HI21: // 275
6194ed0d50c3Schristos case elfcpp::R_AARCH64_ADR_PREL_PG_HI21_NC: // 276
6195ed0d50c3Schristos case elfcpp::R_AARCH64_ADD_ABS_LO12_NC: // 277
6196ed0d50c3Schristos case elfcpp::R_AARCH64_LDST8_ABS_LO12_NC: // 278
6197ed0d50c3Schristos case elfcpp::R_AARCH64_LDST16_ABS_LO12_NC: // 284
6198ed0d50c3Schristos case elfcpp::R_AARCH64_LDST32_ABS_LO12_NC: // 285
6199ed0d50c3Schristos case elfcpp::R_AARCH64_LDST64_ABS_LO12_NC: // 286
6200ed0d50c3Schristos case elfcpp::R_AARCH64_LDST128_ABS_LO12_NC: // 299
6201ed0d50c3Schristos break;
6202ed0d50c3Schristos
6203ed0d50c3Schristos // Control flow, pc-relative. We don't need to do anything for a relative
6204ed0d50c3Schristos // addressing relocation against a local symbol if it does not reference
6205ed0d50c3Schristos // the GOT.
6206ed0d50c3Schristos case elfcpp::R_AARCH64_TSTBR14:
6207ed0d50c3Schristos case elfcpp::R_AARCH64_CONDBR19:
6208ed0d50c3Schristos case elfcpp::R_AARCH64_JUMP26:
6209ed0d50c3Schristos case elfcpp::R_AARCH64_CALL26:
6210ed0d50c3Schristos break;
6211ed0d50c3Schristos
6212ed0d50c3Schristos case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
6213ed0d50c3Schristos case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
6214ed0d50c3Schristos {
6215ed0d50c3Schristos tls::Tls_optimization tlsopt = Target_aarch64<size, big_endian>::
6216ed0d50c3Schristos optimize_tls_reloc(!parameters->options().shared(), r_type);
6217ed0d50c3Schristos if (tlsopt == tls::TLSOPT_TO_LE)
6218ed0d50c3Schristos break;
6219ed0d50c3Schristos
6220ed0d50c3Schristos layout->set_has_static_tls();
6221ed0d50c3Schristos // Create a GOT entry for the tp-relative offset.
6222ed0d50c3Schristos if (!parameters->doing_static_link())
6223ed0d50c3Schristos {
6224ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>* got =
6225ed0d50c3Schristos target->got_section(symtab, layout);
6226ed0d50c3Schristos got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET,
6227ed0d50c3Schristos target->rela_dyn_section(layout),
6228ed0d50c3Schristos elfcpp::R_AARCH64_TLS_TPREL64);
6229ed0d50c3Schristos }
6230ed0d50c3Schristos else if (!object->local_has_got_offset(r_sym,
6231ed0d50c3Schristos GOT_TYPE_TLS_OFFSET))
6232ed0d50c3Schristos {
6233ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>* got =
6234ed0d50c3Schristos target->got_section(symtab, layout);
6235ed0d50c3Schristos got->add_local(object, r_sym, GOT_TYPE_TLS_OFFSET);
6236ed0d50c3Schristos unsigned int got_offset =
6237ed0d50c3Schristos object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET);
6238ed0d50c3Schristos const elfcpp::Elf_Xword addend = rela.get_r_addend();
6239ed0d50c3Schristos gold_assert(addend == 0);
6240ed0d50c3Schristos got->add_static_reloc(got_offset, elfcpp::R_AARCH64_TLS_TPREL64,
6241ed0d50c3Schristos object, r_sym);
6242ed0d50c3Schristos }
6243ed0d50c3Schristos }
6244ed0d50c3Schristos break;
6245ed0d50c3Schristos
6246ed0d50c3Schristos case elfcpp::R_AARCH64_TLSGD_ADR_PAGE21:
6247ed0d50c3Schristos case elfcpp::R_AARCH64_TLSGD_ADD_LO12_NC:
6248ed0d50c3Schristos {
6249ed0d50c3Schristos tls::Tls_optimization tlsopt = Target_aarch64<size, big_endian>::
6250ed0d50c3Schristos optimize_tls_reloc(!parameters->options().shared(), r_type);
6251ed0d50c3Schristos if (tlsopt == tls::TLSOPT_TO_LE)
6252ed0d50c3Schristos {
6253ed0d50c3Schristos layout->set_has_static_tls();
6254ed0d50c3Schristos break;
6255ed0d50c3Schristos }
6256ed0d50c3Schristos gold_assert(tlsopt == tls::TLSOPT_NONE);
6257ed0d50c3Schristos
6258ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>* got =
6259ed0d50c3Schristos target->got_section(symtab, layout);
6260ed0d50c3Schristos got->add_local_pair_with_rel(object,r_sym, data_shndx,
6261ed0d50c3Schristos GOT_TYPE_TLS_PAIR,
6262ed0d50c3Schristos target->rela_dyn_section(layout),
6263ed0d50c3Schristos elfcpp::R_AARCH64_TLS_DTPMOD64);
6264ed0d50c3Schristos }
6265ed0d50c3Schristos break;
6266ed0d50c3Schristos
6267ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G2:
6268ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G1:
6269ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
6270ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G0:
6271ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
6272ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12:
6273ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12:
6274ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
627506324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12:
627606324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
627706324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12:
627806324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
627906324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12:
628006324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
628106324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12:
628206324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
6283ed0d50c3Schristos {
6284ed0d50c3Schristos layout->set_has_static_tls();
6285ed0d50c3Schristos bool output_is_shared = parameters->options().shared();
6286ed0d50c3Schristos if (output_is_shared)
6287ed0d50c3Schristos gold_error(_("%s: unsupported TLSLE reloc %u in shared code."),
6288ed0d50c3Schristos object->name().c_str(), r_type);
6289ed0d50c3Schristos }
6290ed0d50c3Schristos break;
6291ed0d50c3Schristos
6292ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADR_PAGE21:
6293ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_LO12_NC:
6294ed0d50c3Schristos {
6295ed0d50c3Schristos tls::Tls_optimization tlsopt = Target_aarch64<size, big_endian>::
6296ed0d50c3Schristos optimize_tls_reloc(!parameters->options().shared(), r_type);
6297ed0d50c3Schristos if (tlsopt == tls::TLSOPT_NONE)
6298ed0d50c3Schristos {
6299ed0d50c3Schristos // Create a GOT entry for the module index.
6300ed0d50c3Schristos target->got_mod_index_entry(symtab, layout, object);
6301ed0d50c3Schristos }
6302ed0d50c3Schristos else if (tlsopt != tls::TLSOPT_TO_LE)
6303ed0d50c3Schristos unsupported_reloc_local(object, r_type);
6304ed0d50c3Schristos }
6305ed0d50c3Schristos break;
6306ed0d50c3Schristos
6307ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G1:
6308ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC:
6309ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_HI12:
6310ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC:
6311ed0d50c3Schristos break;
6312ed0d50c3Schristos
6313ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADR_PAGE21:
6314ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_LD64_LO12:
6315ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADD_LO12:
6316ed0d50c3Schristos {
6317ed0d50c3Schristos tls::Tls_optimization tlsopt = Target_aarch64<size, big_endian>::
6318ed0d50c3Schristos optimize_tls_reloc(!parameters->options().shared(), r_type);
6319ed0d50c3Schristos target->define_tls_base_symbol(symtab, layout);
6320ed0d50c3Schristos if (tlsopt == tls::TLSOPT_NONE)
6321ed0d50c3Schristos {
6322ed0d50c3Schristos // Create reserved PLT and GOT entries for the resolver.
6323ed0d50c3Schristos target->reserve_tlsdesc_entries(symtab, layout);
6324ed0d50c3Schristos
6325ed0d50c3Schristos // Generate a double GOT entry with an R_AARCH64_TLSDESC reloc.
6326ed0d50c3Schristos // The R_AARCH64_TLSDESC reloc is resolved lazily, so the GOT
6327ed0d50c3Schristos // entry needs to be in an area in .got.plt, not .got. Call
6328ed0d50c3Schristos // got_section to make sure the section has been created.
6329ed0d50c3Schristos target->got_section(symtab, layout);
6330ed0d50c3Schristos Output_data_got<size, big_endian>* got =
6331ed0d50c3Schristos target->got_tlsdesc_section();
6332ed0d50c3Schristos unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
6333ed0d50c3Schristos if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC))
6334ed0d50c3Schristos {
6335ed0d50c3Schristos unsigned int got_offset = got->add_constant(0);
6336ed0d50c3Schristos got->add_constant(0);
6337ed0d50c3Schristos object->set_local_got_offset(r_sym, GOT_TYPE_TLS_DESC,
6338ed0d50c3Schristos got_offset);
6339ed0d50c3Schristos Reloc_section* rt = target->rela_tlsdesc_section(layout);
6340ed0d50c3Schristos // We store the arguments we need in a vector, and use
6341ed0d50c3Schristos // the index into the vector as the parameter to pass
6342ed0d50c3Schristos // to the target specific routines.
6343ed0d50c3Schristos uintptr_t intarg = target->add_tlsdesc_info(object, r_sym);
6344ed0d50c3Schristos void* arg = reinterpret_cast<void*>(intarg);
6345ed0d50c3Schristos rt->add_target_specific(elfcpp::R_AARCH64_TLSDESC, arg,
6346ed0d50c3Schristos got, got_offset, 0);
6347ed0d50c3Schristos }
6348ed0d50c3Schristos }
6349ed0d50c3Schristos else if (tlsopt != tls::TLSOPT_TO_LE)
6350ed0d50c3Schristos unsupported_reloc_local(object, r_type);
6351ed0d50c3Schristos }
6352ed0d50c3Schristos break;
6353ed0d50c3Schristos
6354ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_CALL:
6355ed0d50c3Schristos break;
6356ed0d50c3Schristos
6357ed0d50c3Schristos default:
6358ed0d50c3Schristos unsupported_reloc_local(object, r_type);
6359ed0d50c3Schristos }
6360ed0d50c3Schristos }
6361ed0d50c3Schristos
6362ed0d50c3Schristos
6363ed0d50c3Schristos // Report an unsupported relocation against a global symbol.
6364ed0d50c3Schristos
6365ed0d50c3Schristos template<int size, bool big_endian>
6366ed0d50c3Schristos void
unsupported_reloc_global(Sized_relobj_file<size,big_endian> * object,unsigned int r_type,Symbol * gsym)6367ed0d50c3Schristos Target_aarch64<size, big_endian>::Scan::unsupported_reloc_global(
6368ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object,
6369ed0d50c3Schristos unsigned int r_type,
6370ed0d50c3Schristos Symbol* gsym)
6371ed0d50c3Schristos {
6372ed0d50c3Schristos gold_error(_("%s: unsupported reloc %u against global symbol %s"),
6373ed0d50c3Schristos object->name().c_str(), r_type, gsym->demangled_name().c_str());
6374ed0d50c3Schristos }
6375ed0d50c3Schristos
6376ed0d50c3Schristos template<int size, bool big_endian>
6377ed0d50c3Schristos inline void
global(Symbol_table * symtab,Layout * layout,Target_aarch64<size,big_endian> * target,Sized_relobj_file<size,big_endian> * object,unsigned int data_shndx,Output_section * output_section,const elfcpp::Rela<size,big_endian> & rela,unsigned int r_type,Symbol * gsym)6378ed0d50c3Schristos Target_aarch64<size, big_endian>::Scan::global(
6379ed0d50c3Schristos Symbol_table* symtab,
6380ed0d50c3Schristos Layout* layout,
6381ed0d50c3Schristos Target_aarch64<size, big_endian>* target,
6382ed0d50c3Schristos Sized_relobj_file<size, big_endian> * object,
6383ed0d50c3Schristos unsigned int data_shndx,
6384ed0d50c3Schristos Output_section* output_section,
6385ed0d50c3Schristos const elfcpp::Rela<size, big_endian>& rela,
6386ed0d50c3Schristos unsigned int r_type,
6387ed0d50c3Schristos Symbol* gsym)
6388ed0d50c3Schristos {
6389ed0d50c3Schristos // A STT_GNU_IFUNC symbol may require a PLT entry.
6390ed0d50c3Schristos if (gsym->type() == elfcpp::STT_GNU_IFUNC
6391ed0d50c3Schristos && this->reloc_needs_plt_for_ifunc(object, r_type))
6392ed0d50c3Schristos target->make_plt_entry(symtab, layout, gsym);
6393ed0d50c3Schristos
6394ed0d50c3Schristos typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>
6395ed0d50c3Schristos Reloc_section;
6396ed0d50c3Schristos const AArch64_reloc_property* arp =
6397ed0d50c3Schristos aarch64_reloc_property_table->get_reloc_property(r_type);
6398ed0d50c3Schristos gold_assert(arp != NULL);
6399ed0d50c3Schristos
6400ed0d50c3Schristos switch (r_type)
6401ed0d50c3Schristos {
6402ed0d50c3Schristos case elfcpp::R_AARCH64_NONE:
6403ed0d50c3Schristos break;
6404ed0d50c3Schristos
6405ed0d50c3Schristos case elfcpp::R_AARCH64_ABS16:
6406ed0d50c3Schristos case elfcpp::R_AARCH64_ABS32:
6407ed0d50c3Schristos case elfcpp::R_AARCH64_ABS64:
6408ed0d50c3Schristos {
6409ed0d50c3Schristos // Make a PLT entry if necessary.
6410ed0d50c3Schristos if (gsym->needs_plt_entry())
6411ed0d50c3Schristos {
6412ed0d50c3Schristos target->make_plt_entry(symtab, layout, gsym);
6413ed0d50c3Schristos // Since this is not a PC-relative relocation, we may be
6414ed0d50c3Schristos // taking the address of a function. In that case we need to
6415ed0d50c3Schristos // set the entry in the dynamic symbol table to the address of
6416ed0d50c3Schristos // the PLT entry.
6417ed0d50c3Schristos if (gsym->is_from_dynobj() && !parameters->options().shared())
6418ed0d50c3Schristos gsym->set_needs_dynsym_value();
6419ed0d50c3Schristos }
6420ed0d50c3Schristos // Make a dynamic relocation if necessary.
6421ed0d50c3Schristos if (gsym->needs_dynamic_reloc(arp->reference_flags()))
6422ed0d50c3Schristos {
6423ed0d50c3Schristos if (!parameters->options().output_is_position_independent()
6424ed0d50c3Schristos && gsym->may_need_copy_reloc())
6425ed0d50c3Schristos {
6426ed0d50c3Schristos target->copy_reloc(symtab, layout, object,
6427ed0d50c3Schristos data_shndx, output_section, gsym, rela);
6428ed0d50c3Schristos }
6429ed0d50c3Schristos else if (r_type == elfcpp::R_AARCH64_ABS64
6430ed0d50c3Schristos && gsym->type() == elfcpp::STT_GNU_IFUNC
6431ed0d50c3Schristos && gsym->can_use_relative_reloc(false)
6432ed0d50c3Schristos && !gsym->is_from_dynobj()
6433ed0d50c3Schristos && !gsym->is_undefined()
6434ed0d50c3Schristos && !gsym->is_preemptible())
6435ed0d50c3Schristos {
6436ed0d50c3Schristos // Use an IRELATIVE reloc for a locally defined STT_GNU_IFUNC
6437ed0d50c3Schristos // symbol. This makes a function address in a PIE executable
6438ed0d50c3Schristos // match the address in a shared library that it links against.
6439ed0d50c3Schristos Reloc_section* rela_dyn =
6440ed0d50c3Schristos target->rela_irelative_section(layout);
6441ed0d50c3Schristos unsigned int r_type = elfcpp::R_AARCH64_IRELATIVE;
6442ed0d50c3Schristos rela_dyn->add_symbolless_global_addend(gsym, r_type,
6443ed0d50c3Schristos output_section, object,
6444ed0d50c3Schristos data_shndx,
6445ed0d50c3Schristos rela.get_r_offset(),
6446ed0d50c3Schristos rela.get_r_addend());
6447ed0d50c3Schristos }
6448ed0d50c3Schristos else if (r_type == elfcpp::R_AARCH64_ABS64
6449ed0d50c3Schristos && gsym->can_use_relative_reloc(false))
6450ed0d50c3Schristos {
6451ed0d50c3Schristos Reloc_section* rela_dyn = target->rela_dyn_section(layout);
6452ed0d50c3Schristos rela_dyn->add_global_relative(gsym,
6453ed0d50c3Schristos elfcpp::R_AARCH64_RELATIVE,
6454ed0d50c3Schristos output_section,
6455ed0d50c3Schristos object,
6456ed0d50c3Schristos data_shndx,
6457ed0d50c3Schristos rela.get_r_offset(),
6458ed0d50c3Schristos rela.get_r_addend(),
6459ed0d50c3Schristos false);
6460ed0d50c3Schristos }
6461ed0d50c3Schristos else
6462ed0d50c3Schristos {
6463ed0d50c3Schristos check_non_pic(object, r_type);
6464ed0d50c3Schristos Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>*
6465ed0d50c3Schristos rela_dyn = target->rela_dyn_section(layout);
6466ed0d50c3Schristos rela_dyn->add_global(
6467ed0d50c3Schristos gsym, r_type, output_section, object,
6468ed0d50c3Schristos data_shndx, rela.get_r_offset(),rela.get_r_addend());
6469ed0d50c3Schristos }
6470ed0d50c3Schristos }
6471ed0d50c3Schristos }
6472ed0d50c3Schristos break;
6473ed0d50c3Schristos
6474ed0d50c3Schristos case elfcpp::R_AARCH64_PREL16:
6475ed0d50c3Schristos case elfcpp::R_AARCH64_PREL32:
6476ed0d50c3Schristos case elfcpp::R_AARCH64_PREL64:
6477ed0d50c3Schristos // This is used to fill the GOT absolute address.
6478ed0d50c3Schristos if (gsym->needs_plt_entry())
6479ed0d50c3Schristos {
6480ed0d50c3Schristos target->make_plt_entry(symtab, layout, gsym);
6481ed0d50c3Schristos }
6482ed0d50c3Schristos break;
6483ed0d50c3Schristos
648406324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G0: // 263
648506324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G0_NC: // 264
648606324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G1: // 265
648706324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G1_NC: // 266
648806324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G2: // 267
648906324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G2_NC: // 268
649006324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G3: // 269
649106324dcfSchristos case elfcpp::R_AARCH64_MOVW_SABS_G0: // 270
649206324dcfSchristos case elfcpp::R_AARCH64_MOVW_SABS_G1: // 271
649306324dcfSchristos case elfcpp::R_AARCH64_MOVW_SABS_G2: // 272
649406324dcfSchristos if (parameters->options().output_is_position_independent())
649506324dcfSchristos {
649606324dcfSchristos gold_error(_("%s: unsupported reloc %u in pos independent link."),
649706324dcfSchristos object->name().c_str(), r_type);
649806324dcfSchristos }
6499*b88e3e88Schristos // Make a PLT entry if necessary.
6500*b88e3e88Schristos if (gsym->needs_plt_entry())
6501*b88e3e88Schristos {
6502*b88e3e88Schristos target->make_plt_entry(symtab, layout, gsym);
6503*b88e3e88Schristos // Since this is not a PC-relative relocation, we may be
6504*b88e3e88Schristos // taking the address of a function. In that case we need to
6505*b88e3e88Schristos // set the entry in the dynamic symbol table to the address of
6506*b88e3e88Schristos // the PLT entry.
6507*b88e3e88Schristos if (gsym->is_from_dynobj() && !parameters->options().shared())
6508*b88e3e88Schristos gsym->set_needs_dynsym_value();
6509*b88e3e88Schristos }
651006324dcfSchristos break;
651106324dcfSchristos
6512ed0d50c3Schristos case elfcpp::R_AARCH64_LD_PREL_LO19: // 273
6513ed0d50c3Schristos case elfcpp::R_AARCH64_ADR_PREL_LO21: // 274
6514ed0d50c3Schristos case elfcpp::R_AARCH64_ADR_PREL_PG_HI21: // 275
6515ed0d50c3Schristos case elfcpp::R_AARCH64_ADR_PREL_PG_HI21_NC: // 276
6516ed0d50c3Schristos case elfcpp::R_AARCH64_ADD_ABS_LO12_NC: // 277
6517ed0d50c3Schristos case elfcpp::R_AARCH64_LDST8_ABS_LO12_NC: // 278
6518ed0d50c3Schristos case elfcpp::R_AARCH64_LDST16_ABS_LO12_NC: // 284
6519ed0d50c3Schristos case elfcpp::R_AARCH64_LDST32_ABS_LO12_NC: // 285
6520ed0d50c3Schristos case elfcpp::R_AARCH64_LDST64_ABS_LO12_NC: // 286
6521ed0d50c3Schristos case elfcpp::R_AARCH64_LDST128_ABS_LO12_NC: // 299
6522ed0d50c3Schristos {
6523ed0d50c3Schristos if (gsym->needs_plt_entry())
6524ed0d50c3Schristos target->make_plt_entry(symtab, layout, gsym);
6525ed0d50c3Schristos // Make a dynamic relocation if necessary.
6526ed0d50c3Schristos if (gsym->needs_dynamic_reloc(arp->reference_flags()))
6527ed0d50c3Schristos {
6528ed0d50c3Schristos if (parameters->options().output_is_executable()
6529ed0d50c3Schristos && gsym->may_need_copy_reloc())
6530ed0d50c3Schristos {
6531ed0d50c3Schristos target->copy_reloc(symtab, layout, object,
6532ed0d50c3Schristos data_shndx, output_section, gsym, rela);
6533ed0d50c3Schristos }
6534ed0d50c3Schristos }
6535ed0d50c3Schristos break;
6536ed0d50c3Schristos }
6537ed0d50c3Schristos
6538ed0d50c3Schristos case elfcpp::R_AARCH64_ADR_GOT_PAGE:
6539ed0d50c3Schristos case elfcpp::R_AARCH64_LD64_GOT_LO12_NC:
6540ed0d50c3Schristos case elfcpp::R_AARCH64_LD64_GOTPAGE_LO15:
6541ed0d50c3Schristos {
6542ed0d50c3Schristos // The above relocations are used to access GOT entries.
6543ed0d50c3Schristos // Note a GOT entry is an *address* to a symbol.
6544ed0d50c3Schristos // The symbol requires a GOT entry
6545ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>* got =
6546ed0d50c3Schristos target->got_section(symtab, layout);
6547ed0d50c3Schristos if (gsym->final_value_is_known())
6548ed0d50c3Schristos {
6549ed0d50c3Schristos // For a STT_GNU_IFUNC symbol we want the PLT address.
6550ed0d50c3Schristos if (gsym->type() == elfcpp::STT_GNU_IFUNC)
6551ed0d50c3Schristos got->add_global_plt(gsym, GOT_TYPE_STANDARD);
6552ed0d50c3Schristos else
6553ed0d50c3Schristos got->add_global(gsym, GOT_TYPE_STANDARD);
6554ed0d50c3Schristos }
6555ed0d50c3Schristos else
6556ed0d50c3Schristos {
6557ed0d50c3Schristos // If this symbol is not fully resolved, we need to add a dynamic
6558ed0d50c3Schristos // relocation for it.
6559ed0d50c3Schristos Reloc_section* rela_dyn = target->rela_dyn_section(layout);
6560ed0d50c3Schristos
6561ed0d50c3Schristos // Use a GLOB_DAT rather than a RELATIVE reloc if:
6562ed0d50c3Schristos //
6563ed0d50c3Schristos // 1) The symbol may be defined in some other module.
6564ed0d50c3Schristos // 2) We are building a shared library and this is a protected
6565ed0d50c3Schristos // symbol; using GLOB_DAT means that the dynamic linker can use
6566ed0d50c3Schristos // the address of the PLT in the main executable when appropriate
6567ed0d50c3Schristos // so that function address comparisons work.
6568ed0d50c3Schristos // 3) This is a STT_GNU_IFUNC symbol in position dependent code,
6569ed0d50c3Schristos // again so that function address comparisons work.
6570ed0d50c3Schristos if (gsym->is_from_dynobj()
6571ed0d50c3Schristos || gsym->is_undefined()
6572ed0d50c3Schristos || gsym->is_preemptible()
6573ed0d50c3Schristos || (gsym->visibility() == elfcpp::STV_PROTECTED
6574ed0d50c3Schristos && parameters->options().shared())
6575ed0d50c3Schristos || (gsym->type() == elfcpp::STT_GNU_IFUNC
6576ed0d50c3Schristos && parameters->options().output_is_position_independent()))
6577ed0d50c3Schristos got->add_global_with_rel(gsym, GOT_TYPE_STANDARD,
6578ed0d50c3Schristos rela_dyn, elfcpp::R_AARCH64_GLOB_DAT);
6579ed0d50c3Schristos else
6580ed0d50c3Schristos {
6581ed0d50c3Schristos // For a STT_GNU_IFUNC symbol we want to write the PLT
6582ed0d50c3Schristos // offset into the GOT, so that function pointer
6583ed0d50c3Schristos // comparisons work correctly.
6584ed0d50c3Schristos bool is_new;
6585ed0d50c3Schristos if (gsym->type() != elfcpp::STT_GNU_IFUNC)
6586ed0d50c3Schristos is_new = got->add_global(gsym, GOT_TYPE_STANDARD);
6587ed0d50c3Schristos else
6588ed0d50c3Schristos {
6589ed0d50c3Schristos is_new = got->add_global_plt(gsym, GOT_TYPE_STANDARD);
6590ed0d50c3Schristos // Tell the dynamic linker to use the PLT address
6591ed0d50c3Schristos // when resolving relocations.
6592ed0d50c3Schristos if (gsym->is_from_dynobj()
6593ed0d50c3Schristos && !parameters->options().shared())
6594ed0d50c3Schristos gsym->set_needs_dynsym_value();
6595ed0d50c3Schristos }
6596ed0d50c3Schristos if (is_new)
6597ed0d50c3Schristos {
6598ed0d50c3Schristos rela_dyn->add_global_relative(
6599ed0d50c3Schristos gsym, elfcpp::R_AARCH64_RELATIVE,
6600ed0d50c3Schristos got,
6601ed0d50c3Schristos gsym->got_offset(GOT_TYPE_STANDARD),
6602ed0d50c3Schristos 0,
6603ed0d50c3Schristos false);
6604ed0d50c3Schristos }
6605ed0d50c3Schristos }
6606ed0d50c3Schristos }
6607ed0d50c3Schristos break;
6608ed0d50c3Schristos }
6609ed0d50c3Schristos
6610ed0d50c3Schristos case elfcpp::R_AARCH64_TSTBR14:
6611ed0d50c3Schristos case elfcpp::R_AARCH64_CONDBR19:
6612ed0d50c3Schristos case elfcpp::R_AARCH64_JUMP26:
6613ed0d50c3Schristos case elfcpp::R_AARCH64_CALL26:
6614ed0d50c3Schristos {
6615ed0d50c3Schristos if (gsym->final_value_is_known())
6616ed0d50c3Schristos break;
6617ed0d50c3Schristos
6618ed0d50c3Schristos if (gsym->is_defined() &&
6619ed0d50c3Schristos !gsym->is_from_dynobj() &&
6620ed0d50c3Schristos !gsym->is_preemptible())
6621ed0d50c3Schristos break;
6622ed0d50c3Schristos
6623ed0d50c3Schristos // Make plt entry for function call.
6624ed0d50c3Schristos target->make_plt_entry(symtab, layout, gsym);
6625ed0d50c3Schristos break;
6626ed0d50c3Schristos }
6627ed0d50c3Schristos
6628ed0d50c3Schristos case elfcpp::R_AARCH64_TLSGD_ADR_PAGE21:
6629ed0d50c3Schristos case elfcpp::R_AARCH64_TLSGD_ADD_LO12_NC: // General dynamic
6630ed0d50c3Schristos {
6631ed0d50c3Schristos tls::Tls_optimization tlsopt = Target_aarch64<size, big_endian>::
6632ed0d50c3Schristos optimize_tls_reloc(gsym->final_value_is_known(), r_type);
6633ed0d50c3Schristos if (tlsopt == tls::TLSOPT_TO_LE)
6634ed0d50c3Schristos {
6635ed0d50c3Schristos layout->set_has_static_tls();
6636ed0d50c3Schristos break;
6637ed0d50c3Schristos }
6638ed0d50c3Schristos gold_assert(tlsopt == tls::TLSOPT_NONE);
6639ed0d50c3Schristos
6640ed0d50c3Schristos // General dynamic.
6641ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>* got =
6642ed0d50c3Schristos target->got_section(symtab, layout);
6643ed0d50c3Schristos // Create 2 consecutive entries for module index and offset.
6644ed0d50c3Schristos got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
6645ed0d50c3Schristos target->rela_dyn_section(layout),
6646ed0d50c3Schristos elfcpp::R_AARCH64_TLS_DTPMOD64,
6647ed0d50c3Schristos elfcpp::R_AARCH64_TLS_DTPREL64);
6648ed0d50c3Schristos }
6649ed0d50c3Schristos break;
6650ed0d50c3Schristos
6651ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADR_PAGE21:
6652ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_LO12_NC: // Local dynamic
6653ed0d50c3Schristos {
6654ed0d50c3Schristos tls::Tls_optimization tlsopt = Target_aarch64<size, big_endian>::
6655ed0d50c3Schristos optimize_tls_reloc(!parameters->options().shared(), r_type);
6656ed0d50c3Schristos if (tlsopt == tls::TLSOPT_NONE)
6657ed0d50c3Schristos {
6658ed0d50c3Schristos // Create a GOT entry for the module index.
6659ed0d50c3Schristos target->got_mod_index_entry(symtab, layout, object);
6660ed0d50c3Schristos }
6661ed0d50c3Schristos else if (tlsopt != tls::TLSOPT_TO_LE)
6662ed0d50c3Schristos unsupported_reloc_local(object, r_type);
6663ed0d50c3Schristos }
6664ed0d50c3Schristos break;
6665ed0d50c3Schristos
6666ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G1:
6667ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC:
6668ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_HI12:
6669ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: // Other local dynamic
6670ed0d50c3Schristos break;
6671ed0d50c3Schristos
6672ed0d50c3Schristos case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
6673ed0d50c3Schristos case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: // Initial executable
6674ed0d50c3Schristos {
6675ed0d50c3Schristos tls::Tls_optimization tlsopt = Target_aarch64<size, big_endian>::
6676ed0d50c3Schristos optimize_tls_reloc(gsym->final_value_is_known(), r_type);
6677ed0d50c3Schristos if (tlsopt == tls::TLSOPT_TO_LE)
6678ed0d50c3Schristos break;
6679ed0d50c3Schristos
6680ed0d50c3Schristos layout->set_has_static_tls();
6681ed0d50c3Schristos // Create a GOT entry for the tp-relative offset.
6682ed0d50c3Schristos Output_data_got_aarch64<size, big_endian>* got
6683ed0d50c3Schristos = target->got_section(symtab, layout);
6684ed0d50c3Schristos if (!parameters->doing_static_link())
6685ed0d50c3Schristos {
6686ed0d50c3Schristos got->add_global_with_rel(
6687ed0d50c3Schristos gsym, GOT_TYPE_TLS_OFFSET,
6688ed0d50c3Schristos target->rela_dyn_section(layout),
6689ed0d50c3Schristos elfcpp::R_AARCH64_TLS_TPREL64);
6690ed0d50c3Schristos }
6691ed0d50c3Schristos if (!gsym->has_got_offset(GOT_TYPE_TLS_OFFSET))
6692ed0d50c3Schristos {
6693ed0d50c3Schristos got->add_global(gsym, GOT_TYPE_TLS_OFFSET);
6694ed0d50c3Schristos unsigned int got_offset =
6695ed0d50c3Schristos gsym->got_offset(GOT_TYPE_TLS_OFFSET);
6696ed0d50c3Schristos const elfcpp::Elf_Xword addend = rela.get_r_addend();
6697ed0d50c3Schristos gold_assert(addend == 0);
6698ed0d50c3Schristos got->add_static_reloc(got_offset,
6699ed0d50c3Schristos elfcpp::R_AARCH64_TLS_TPREL64, gsym);
6700ed0d50c3Schristos }
6701ed0d50c3Schristos }
6702ed0d50c3Schristos break;
6703ed0d50c3Schristos
6704ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G2:
6705ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G1:
6706ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
6707ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G0:
6708ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
6709ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12:
6710ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12:
671106324dcfSchristos case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
671206324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12:
671306324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
671406324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12:
671506324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
671606324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12:
671706324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
671806324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12:
671906324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: // Local executable
6720ed0d50c3Schristos layout->set_has_static_tls();
6721ed0d50c3Schristos if (parameters->options().shared())
6722ed0d50c3Schristos gold_error(_("%s: unsupported TLSLE reloc type %u in shared objects."),
6723ed0d50c3Schristos object->name().c_str(), r_type);
6724ed0d50c3Schristos break;
6725ed0d50c3Schristos
6726ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADR_PAGE21:
6727ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_LD64_LO12:
6728ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADD_LO12: // TLS descriptor
6729ed0d50c3Schristos {
6730ed0d50c3Schristos target->define_tls_base_symbol(symtab, layout);
6731ed0d50c3Schristos tls::Tls_optimization tlsopt = Target_aarch64<size, big_endian>::
6732ed0d50c3Schristos optimize_tls_reloc(gsym->final_value_is_known(), r_type);
6733ed0d50c3Schristos if (tlsopt == tls::TLSOPT_NONE)
6734ed0d50c3Schristos {
6735ed0d50c3Schristos // Create reserved PLT and GOT entries for the resolver.
6736ed0d50c3Schristos target->reserve_tlsdesc_entries(symtab, layout);
6737ed0d50c3Schristos
6738ed0d50c3Schristos // Create a double GOT entry with an R_AARCH64_TLSDESC
6739ed0d50c3Schristos // relocation. The R_AARCH64_TLSDESC is resolved lazily, so the GOT
6740ed0d50c3Schristos // entry needs to be in an area in .got.plt, not .got. Call
6741ed0d50c3Schristos // got_section to make sure the section has been created.
6742ed0d50c3Schristos target->got_section(symtab, layout);
6743ed0d50c3Schristos Output_data_got<size, big_endian>* got =
6744ed0d50c3Schristos target->got_tlsdesc_section();
6745ed0d50c3Schristos Reloc_section* rt = target->rela_tlsdesc_section(layout);
6746ed0d50c3Schristos got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_DESC, rt,
6747ed0d50c3Schristos elfcpp::R_AARCH64_TLSDESC, 0);
6748ed0d50c3Schristos }
6749ed0d50c3Schristos else if (tlsopt == tls::TLSOPT_TO_IE)
6750ed0d50c3Schristos {
6751ed0d50c3Schristos // Create a GOT entry for the tp-relative offset.
6752ed0d50c3Schristos Output_data_got<size, big_endian>* got
6753ed0d50c3Schristos = target->got_section(symtab, layout);
6754ed0d50c3Schristos got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
6755ed0d50c3Schristos target->rela_dyn_section(layout),
6756ed0d50c3Schristos elfcpp::R_AARCH64_TLS_TPREL64);
6757ed0d50c3Schristos }
6758ed0d50c3Schristos else if (tlsopt != tls::TLSOPT_TO_LE)
6759ed0d50c3Schristos unsupported_reloc_global(object, r_type, gsym);
6760ed0d50c3Schristos }
6761ed0d50c3Schristos break;
6762ed0d50c3Schristos
6763ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_CALL:
6764ed0d50c3Schristos break;
6765ed0d50c3Schristos
6766ed0d50c3Schristos default:
6767ed0d50c3Schristos gold_error(_("%s: unsupported reloc type in global scan"),
6768ed0d50c3Schristos aarch64_reloc_property_table->
6769ed0d50c3Schristos reloc_name_in_error_message(r_type).c_str());
6770ed0d50c3Schristos }
6771ed0d50c3Schristos return;
6772ed0d50c3Schristos } // End of Scan::global
6773ed0d50c3Schristos
6774ed0d50c3Schristos
6775ed0d50c3Schristos // Create the PLT section.
6776ed0d50c3Schristos template<int size, bool big_endian>
6777ed0d50c3Schristos void
make_plt_section(Symbol_table * symtab,Layout * layout)6778ed0d50c3Schristos Target_aarch64<size, big_endian>::make_plt_section(
6779ed0d50c3Schristos Symbol_table* symtab, Layout* layout)
6780ed0d50c3Schristos {
6781ed0d50c3Schristos if (this->plt_ == NULL)
6782ed0d50c3Schristos {
6783ed0d50c3Schristos // Create the GOT section first.
6784ed0d50c3Schristos this->got_section(symtab, layout);
6785ed0d50c3Schristos
6786ed0d50c3Schristos this->plt_ = this->make_data_plt(layout, this->got_, this->got_plt_,
6787ed0d50c3Schristos this->got_irelative_);
6788ed0d50c3Schristos
6789ed0d50c3Schristos layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
6790ed0d50c3Schristos (elfcpp::SHF_ALLOC
6791ed0d50c3Schristos | elfcpp::SHF_EXECINSTR),
6792ed0d50c3Schristos this->plt_, ORDER_PLT, false);
6793ed0d50c3Schristos
6794ed0d50c3Schristos // Make the sh_info field of .rela.plt point to .plt.
6795ed0d50c3Schristos Output_section* rela_plt_os = this->plt_->rela_plt()->output_section();
6796ed0d50c3Schristos rela_plt_os->set_info_section(this->plt_->output_section());
6797ed0d50c3Schristos }
6798ed0d50c3Schristos }
6799ed0d50c3Schristos
6800ed0d50c3Schristos // Return the section for TLSDESC relocations.
6801ed0d50c3Schristos
6802ed0d50c3Schristos template<int size, bool big_endian>
6803ed0d50c3Schristos typename Target_aarch64<size, big_endian>::Reloc_section*
rela_tlsdesc_section(Layout * layout) const6804ed0d50c3Schristos Target_aarch64<size, big_endian>::rela_tlsdesc_section(Layout* layout) const
6805ed0d50c3Schristos {
6806ed0d50c3Schristos return this->plt_section()->rela_tlsdesc(layout);
6807ed0d50c3Schristos }
6808ed0d50c3Schristos
6809ed0d50c3Schristos // Create a PLT entry for a global symbol.
6810ed0d50c3Schristos
6811ed0d50c3Schristos template<int size, bool big_endian>
6812ed0d50c3Schristos void
make_plt_entry(Symbol_table * symtab,Layout * layout,Symbol * gsym)6813ed0d50c3Schristos Target_aarch64<size, big_endian>::make_plt_entry(
6814ed0d50c3Schristos Symbol_table* symtab,
6815ed0d50c3Schristos Layout* layout,
6816ed0d50c3Schristos Symbol* gsym)
6817ed0d50c3Schristos {
6818ed0d50c3Schristos if (gsym->has_plt_offset())
6819ed0d50c3Schristos return;
6820ed0d50c3Schristos
6821ed0d50c3Schristos if (this->plt_ == NULL)
6822ed0d50c3Schristos this->make_plt_section(symtab, layout);
6823ed0d50c3Schristos
6824ed0d50c3Schristos this->plt_->add_entry(symtab, layout, gsym);
6825ed0d50c3Schristos }
6826ed0d50c3Schristos
6827ed0d50c3Schristos // Make a PLT entry for a local STT_GNU_IFUNC symbol.
6828ed0d50c3Schristos
6829ed0d50c3Schristos template<int size, bool big_endian>
6830ed0d50c3Schristos void
make_local_ifunc_plt_entry(Symbol_table * symtab,Layout * layout,Sized_relobj_file<size,big_endian> * relobj,unsigned int local_sym_index)6831ed0d50c3Schristos Target_aarch64<size, big_endian>::make_local_ifunc_plt_entry(
6832ed0d50c3Schristos Symbol_table* symtab, Layout* layout,
6833ed0d50c3Schristos Sized_relobj_file<size, big_endian>* relobj,
6834ed0d50c3Schristos unsigned int local_sym_index)
6835ed0d50c3Schristos {
6836ed0d50c3Schristos if (relobj->local_has_plt_offset(local_sym_index))
6837ed0d50c3Schristos return;
6838ed0d50c3Schristos if (this->plt_ == NULL)
6839ed0d50c3Schristos this->make_plt_section(symtab, layout);
6840ed0d50c3Schristos unsigned int plt_offset = this->plt_->add_local_ifunc_entry(symtab, layout,
6841ed0d50c3Schristos relobj,
6842ed0d50c3Schristos local_sym_index);
6843ed0d50c3Schristos relobj->set_local_plt_offset(local_sym_index, plt_offset);
6844ed0d50c3Schristos }
6845ed0d50c3Schristos
6846ed0d50c3Schristos template<int size, bool big_endian>
6847ed0d50c3Schristos void
gc_process_relocs(Symbol_table * symtab,Layout * layout,Sized_relobj_file<size,big_endian> * object,unsigned int data_shndx,unsigned int sh_type,const unsigned char * prelocs,size_t reloc_count,Output_section * output_section,bool needs_special_offset_handling,size_t local_symbol_count,const unsigned char * plocal_symbols)6848ed0d50c3Schristos Target_aarch64<size, big_endian>::gc_process_relocs(
6849ed0d50c3Schristos Symbol_table* symtab,
6850ed0d50c3Schristos Layout* layout,
6851ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object,
6852ed0d50c3Schristos unsigned int data_shndx,
6853ed0d50c3Schristos unsigned int sh_type,
6854ed0d50c3Schristos const unsigned char* prelocs,
6855ed0d50c3Schristos size_t reloc_count,
6856ed0d50c3Schristos Output_section* output_section,
6857ed0d50c3Schristos bool needs_special_offset_handling,
6858ed0d50c3Schristos size_t local_symbol_count,
6859ed0d50c3Schristos const unsigned char* plocal_symbols)
6860ed0d50c3Schristos {
6861ed0d50c3Schristos typedef Target_aarch64<size, big_endian> Aarch64;
6862ed0d50c3Schristos typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
6863ed0d50c3Schristos Classify_reloc;
6864ed0d50c3Schristos
6865ed0d50c3Schristos if (sh_type == elfcpp::SHT_REL)
6866ed0d50c3Schristos {
6867ed0d50c3Schristos return;
6868ed0d50c3Schristos }
6869ed0d50c3Schristos
6870ed0d50c3Schristos gold::gc_process_relocs<size, big_endian, Aarch64, Scan, Classify_reloc>(
6871ed0d50c3Schristos symtab,
6872ed0d50c3Schristos layout,
6873ed0d50c3Schristos this,
6874ed0d50c3Schristos object,
6875ed0d50c3Schristos data_shndx,
6876ed0d50c3Schristos prelocs,
6877ed0d50c3Schristos reloc_count,
6878ed0d50c3Schristos output_section,
6879ed0d50c3Schristos needs_special_offset_handling,
6880ed0d50c3Schristos local_symbol_count,
6881ed0d50c3Schristos plocal_symbols);
6882ed0d50c3Schristos }
6883ed0d50c3Schristos
6884ed0d50c3Schristos // Scan relocations for a section.
6885ed0d50c3Schristos
6886ed0d50c3Schristos template<int size, bool big_endian>
6887ed0d50c3Schristos void
scan_relocs(Symbol_table * symtab,Layout * layout,Sized_relobj_file<size,big_endian> * object,unsigned int data_shndx,unsigned int sh_type,const unsigned char * prelocs,size_t reloc_count,Output_section * output_section,bool needs_special_offset_handling,size_t local_symbol_count,const unsigned char * plocal_symbols)6888ed0d50c3Schristos Target_aarch64<size, big_endian>::scan_relocs(
6889ed0d50c3Schristos Symbol_table* symtab,
6890ed0d50c3Schristos Layout* layout,
6891ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object,
6892ed0d50c3Schristos unsigned int data_shndx,
6893ed0d50c3Schristos unsigned int sh_type,
6894ed0d50c3Schristos const unsigned char* prelocs,
6895ed0d50c3Schristos size_t reloc_count,
6896ed0d50c3Schristos Output_section* output_section,
6897ed0d50c3Schristos bool needs_special_offset_handling,
6898ed0d50c3Schristos size_t local_symbol_count,
6899ed0d50c3Schristos const unsigned char* plocal_symbols)
6900ed0d50c3Schristos {
6901ed0d50c3Schristos typedef Target_aarch64<size, big_endian> Aarch64;
6902ed0d50c3Schristos typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
6903ed0d50c3Schristos Classify_reloc;
6904ed0d50c3Schristos
6905ed0d50c3Schristos if (sh_type == elfcpp::SHT_REL)
6906ed0d50c3Schristos {
6907ed0d50c3Schristos gold_error(_("%s: unsupported REL reloc section"),
6908ed0d50c3Schristos object->name().c_str());
6909ed0d50c3Schristos return;
6910ed0d50c3Schristos }
6911ed0d50c3Schristos
6912ed0d50c3Schristos gold::scan_relocs<size, big_endian, Aarch64, Scan, Classify_reloc>(
6913ed0d50c3Schristos symtab,
6914ed0d50c3Schristos layout,
6915ed0d50c3Schristos this,
6916ed0d50c3Schristos object,
6917ed0d50c3Schristos data_shndx,
6918ed0d50c3Schristos prelocs,
6919ed0d50c3Schristos reloc_count,
6920ed0d50c3Schristos output_section,
6921ed0d50c3Schristos needs_special_offset_handling,
6922ed0d50c3Schristos local_symbol_count,
6923ed0d50c3Schristos plocal_symbols);
6924ed0d50c3Schristos }
6925ed0d50c3Schristos
6926ed0d50c3Schristos // Return the value to use for a dynamic which requires special
6927ed0d50c3Schristos // treatment. This is how we support equality comparisons of function
6928ed0d50c3Schristos // pointers across shared library boundaries, as described in the
6929ed0d50c3Schristos // processor specific ABI supplement.
6930ed0d50c3Schristos
6931ed0d50c3Schristos template<int size, bool big_endian>
6932ed0d50c3Schristos uint64_t
do_dynsym_value(const Symbol * gsym) const6933ed0d50c3Schristos Target_aarch64<size, big_endian>::do_dynsym_value(const Symbol* gsym) const
6934ed0d50c3Schristos {
6935ed0d50c3Schristos gold_assert(gsym->is_from_dynobj() && gsym->has_plt_offset());
6936ed0d50c3Schristos return this->plt_address_for_global(gsym);
6937ed0d50c3Schristos }
6938ed0d50c3Schristos
6939ed0d50c3Schristos
6940ed0d50c3Schristos // Finalize the sections.
6941ed0d50c3Schristos
6942ed0d50c3Schristos template<int size, bool big_endian>
6943ed0d50c3Schristos void
do_finalize_sections(Layout * layout,const Input_objects *,Symbol_table * symtab)6944ed0d50c3Schristos Target_aarch64<size, big_endian>::do_finalize_sections(
6945ed0d50c3Schristos Layout* layout,
6946ed0d50c3Schristos const Input_objects*,
6947ed0d50c3Schristos Symbol_table* symtab)
6948ed0d50c3Schristos {
6949ed0d50c3Schristos const Reloc_section* rel_plt = (this->plt_ == NULL
6950ed0d50c3Schristos ? NULL
6951ed0d50c3Schristos : this->plt_->rela_plt());
6952ed0d50c3Schristos layout->add_target_dynamic_tags(false, this->got_plt_, rel_plt,
6953ed0d50c3Schristos this->rela_dyn_, true, false);
6954ed0d50c3Schristos
6955ed0d50c3Schristos // Emit any relocs we saved in an attempt to avoid generating COPY
6956ed0d50c3Schristos // relocs.
6957ed0d50c3Schristos if (this->copy_relocs_.any_saved_relocs())
6958ed0d50c3Schristos this->copy_relocs_.emit(this->rela_dyn_section(layout));
6959ed0d50c3Schristos
6960ed0d50c3Schristos // Fill in some more dynamic tags.
6961ed0d50c3Schristos Output_data_dynamic* const odyn = layout->dynamic_data();
6962ed0d50c3Schristos if (odyn != NULL)
6963ed0d50c3Schristos {
6964ed0d50c3Schristos if (this->plt_ != NULL
6965ed0d50c3Schristos && this->plt_->output_section() != NULL
6966ed0d50c3Schristos && this->plt_ ->has_tlsdesc_entry())
6967ed0d50c3Schristos {
6968ed0d50c3Schristos unsigned int plt_offset = this->plt_->get_tlsdesc_plt_offset();
6969ed0d50c3Schristos unsigned int got_offset = this->plt_->get_tlsdesc_got_offset();
6970ed0d50c3Schristos this->got_->finalize_data_size();
6971ed0d50c3Schristos odyn->add_section_plus_offset(elfcpp::DT_TLSDESC_PLT,
6972ed0d50c3Schristos this->plt_, plt_offset);
6973ed0d50c3Schristos odyn->add_section_plus_offset(elfcpp::DT_TLSDESC_GOT,
6974ed0d50c3Schristos this->got_, got_offset);
6975ed0d50c3Schristos }
6976ed0d50c3Schristos }
6977ed0d50c3Schristos
6978ed0d50c3Schristos // Set the size of the _GLOBAL_OFFSET_TABLE_ symbol to the size of
697906324dcfSchristos // the .got section.
6980ed0d50c3Schristos Symbol* sym = this->global_offset_table_;
6981ed0d50c3Schristos if (sym != NULL)
6982ed0d50c3Schristos {
698306324dcfSchristos uint64_t data_size = this->got_->current_data_size();
6984ed0d50c3Schristos symtab->get_sized_symbol<size>(sym)->set_symsize(data_size);
6985ed0d50c3Schristos
6986ed0d50c3Schristos // If the .got section is more than 0x8000 bytes, we add
6987ed0d50c3Schristos // 0x8000 to the value of _GLOBAL_OFFSET_TABLE_, so that 16
6988ed0d50c3Schristos // bit relocations have a greater chance of working.
6989ed0d50c3Schristos if (data_size >= 0x8000)
6990ed0d50c3Schristos symtab->get_sized_symbol<size>(sym)->set_value(
6991ed0d50c3Schristos symtab->get_sized_symbol<size>(sym)->value() + 0x8000);
6992ed0d50c3Schristos }
6993ed0d50c3Schristos
6994ed0d50c3Schristos if (parameters->doing_static_link()
6995ed0d50c3Schristos && (this->plt_ == NULL || !this->plt_->has_irelative_section()))
6996ed0d50c3Schristos {
6997ed0d50c3Schristos // If linking statically, make sure that the __rela_iplt symbols
6998ed0d50c3Schristos // were defined if necessary, even if we didn't create a PLT.
6999ed0d50c3Schristos static const Define_symbol_in_segment syms[] =
7000ed0d50c3Schristos {
7001ed0d50c3Schristos {
7002ed0d50c3Schristos "__rela_iplt_start", // name
7003ed0d50c3Schristos elfcpp::PT_LOAD, // segment_type
7004ed0d50c3Schristos elfcpp::PF_W, // segment_flags_set
7005ed0d50c3Schristos elfcpp::PF(0), // segment_flags_clear
7006ed0d50c3Schristos 0, // value
7007ed0d50c3Schristos 0, // size
7008ed0d50c3Schristos elfcpp::STT_NOTYPE, // type
7009ed0d50c3Schristos elfcpp::STB_GLOBAL, // binding
7010ed0d50c3Schristos elfcpp::STV_HIDDEN, // visibility
7011ed0d50c3Schristos 0, // nonvis
7012ed0d50c3Schristos Symbol::SEGMENT_START, // offset_from_base
7013ed0d50c3Schristos true // only_if_ref
7014ed0d50c3Schristos },
7015ed0d50c3Schristos {
7016ed0d50c3Schristos "__rela_iplt_end", // name
7017ed0d50c3Schristos elfcpp::PT_LOAD, // segment_type
7018ed0d50c3Schristos elfcpp::PF_W, // segment_flags_set
7019ed0d50c3Schristos elfcpp::PF(0), // segment_flags_clear
7020ed0d50c3Schristos 0, // value
7021ed0d50c3Schristos 0, // size
7022ed0d50c3Schristos elfcpp::STT_NOTYPE, // type
7023ed0d50c3Schristos elfcpp::STB_GLOBAL, // binding
7024ed0d50c3Schristos elfcpp::STV_HIDDEN, // visibility
7025ed0d50c3Schristos 0, // nonvis
7026ed0d50c3Schristos Symbol::SEGMENT_START, // offset_from_base
7027ed0d50c3Schristos true // only_if_ref
7028ed0d50c3Schristos }
7029ed0d50c3Schristos };
7030ed0d50c3Schristos
7031ed0d50c3Schristos symtab->define_symbols(layout, 2, syms,
7032ed0d50c3Schristos layout->script_options()->saw_sections_clause());
7033ed0d50c3Schristos }
7034ed0d50c3Schristos
7035ed0d50c3Schristos return;
7036ed0d50c3Schristos }
7037ed0d50c3Schristos
7038ed0d50c3Schristos // Perform a relocation.
7039ed0d50c3Schristos
7040ed0d50c3Schristos template<int size, bool big_endian>
7041ed0d50c3Schristos inline bool
relocate(const Relocate_info<size,big_endian> * relinfo,unsigned int,Target_aarch64<size,big_endian> * target,Output_section *,size_t relnum,const unsigned char * preloc,const Sized_symbol<size> * gsym,const Symbol_value<size> * psymval,unsigned char * view,typename elfcpp::Elf_types<size>::Elf_Addr address,section_size_type)7042ed0d50c3Schristos Target_aarch64<size, big_endian>::Relocate::relocate(
7043ed0d50c3Schristos const Relocate_info<size, big_endian>* relinfo,
7044ed0d50c3Schristos unsigned int,
7045ed0d50c3Schristos Target_aarch64<size, big_endian>* target,
7046ed0d50c3Schristos Output_section* ,
7047ed0d50c3Schristos size_t relnum,
7048ed0d50c3Schristos const unsigned char* preloc,
7049ed0d50c3Schristos const Sized_symbol<size>* gsym,
7050ed0d50c3Schristos const Symbol_value<size>* psymval,
7051ed0d50c3Schristos unsigned char* view,
7052ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr address,
7053ed0d50c3Schristos section_size_type /* view_size */)
7054ed0d50c3Schristos {
7055ed0d50c3Schristos if (view == NULL)
7056ed0d50c3Schristos return true;
7057ed0d50c3Schristos
7058ed0d50c3Schristos typedef AArch64_relocate_functions<size, big_endian> Reloc;
7059ed0d50c3Schristos
7060ed0d50c3Schristos const elfcpp::Rela<size, big_endian> rela(preloc);
7061ed0d50c3Schristos unsigned int r_type = elfcpp::elf_r_type<size>(rela.get_r_info());
7062ed0d50c3Schristos const AArch64_reloc_property* reloc_property =
7063ed0d50c3Schristos aarch64_reloc_property_table->get_reloc_property(r_type);
7064ed0d50c3Schristos
7065ed0d50c3Schristos if (reloc_property == NULL)
7066ed0d50c3Schristos {
7067ed0d50c3Schristos std::string reloc_name =
7068ed0d50c3Schristos aarch64_reloc_property_table->reloc_name_in_error_message(r_type);
7069ed0d50c3Schristos gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
7070ed0d50c3Schristos _("cannot relocate %s in object file"),
7071ed0d50c3Schristos reloc_name.c_str());
7072ed0d50c3Schristos return true;
7073ed0d50c3Schristos }
7074ed0d50c3Schristos
7075ed0d50c3Schristos const Sized_relobj_file<size, big_endian>* object = relinfo->object;
7076ed0d50c3Schristos
7077ed0d50c3Schristos // Pick the value to use for symbols defined in the PLT.
7078ed0d50c3Schristos Symbol_value<size> symval;
7079ed0d50c3Schristos if (gsym != NULL
7080ed0d50c3Schristos && gsym->use_plt_offset(reloc_property->reference_flags()))
7081ed0d50c3Schristos {
7082ed0d50c3Schristos symval.set_output_value(target->plt_address_for_global(gsym));
7083ed0d50c3Schristos psymval = &symval;
7084ed0d50c3Schristos }
7085ed0d50c3Schristos else if (gsym == NULL && psymval->is_ifunc_symbol())
7086ed0d50c3Schristos {
7087ed0d50c3Schristos unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
7088ed0d50c3Schristos if (object->local_has_plt_offset(r_sym))
7089ed0d50c3Schristos {
7090ed0d50c3Schristos symval.set_output_value(target->plt_address_for_local(object, r_sym));
7091ed0d50c3Schristos psymval = &symval;
7092ed0d50c3Schristos }
7093ed0d50c3Schristos }
7094ed0d50c3Schristos
7095ed0d50c3Schristos const elfcpp::Elf_Xword addend = rela.get_r_addend();
7096ed0d50c3Schristos
7097ed0d50c3Schristos // Get the GOT offset if needed.
7098ed0d50c3Schristos // For aarch64, the GOT pointer points to the start of the GOT section.
7099ed0d50c3Schristos bool have_got_offset = false;
7100ed0d50c3Schristos int got_offset = 0;
7101ed0d50c3Schristos int got_base = (target->got_ != NULL
7102ed0d50c3Schristos ? (target->got_->current_data_size() >= 0x8000
7103ed0d50c3Schristos ? 0x8000 : 0)
7104ed0d50c3Schristos : 0);
7105ed0d50c3Schristos switch (r_type)
7106ed0d50c3Schristos {
7107ed0d50c3Schristos case elfcpp::R_AARCH64_MOVW_GOTOFF_G0:
7108ed0d50c3Schristos case elfcpp::R_AARCH64_MOVW_GOTOFF_G0_NC:
7109ed0d50c3Schristos case elfcpp::R_AARCH64_MOVW_GOTOFF_G1:
7110ed0d50c3Schristos case elfcpp::R_AARCH64_MOVW_GOTOFF_G1_NC:
7111ed0d50c3Schristos case elfcpp::R_AARCH64_MOVW_GOTOFF_G2:
7112ed0d50c3Schristos case elfcpp::R_AARCH64_MOVW_GOTOFF_G2_NC:
7113ed0d50c3Schristos case elfcpp::R_AARCH64_MOVW_GOTOFF_G3:
7114ed0d50c3Schristos case elfcpp::R_AARCH64_GOTREL64:
7115ed0d50c3Schristos case elfcpp::R_AARCH64_GOTREL32:
7116ed0d50c3Schristos case elfcpp::R_AARCH64_GOT_LD_PREL19:
7117ed0d50c3Schristos case elfcpp::R_AARCH64_LD64_GOTOFF_LO15:
7118ed0d50c3Schristos case elfcpp::R_AARCH64_ADR_GOT_PAGE:
7119ed0d50c3Schristos case elfcpp::R_AARCH64_LD64_GOT_LO12_NC:
7120ed0d50c3Schristos case elfcpp::R_AARCH64_LD64_GOTPAGE_LO15:
7121ed0d50c3Schristos if (gsym != NULL)
7122ed0d50c3Schristos {
7123ed0d50c3Schristos gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
7124ed0d50c3Schristos got_offset = gsym->got_offset(GOT_TYPE_STANDARD) - got_base;
7125ed0d50c3Schristos }
7126ed0d50c3Schristos else
7127ed0d50c3Schristos {
7128ed0d50c3Schristos unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
7129ed0d50c3Schristos gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
7130ed0d50c3Schristos got_offset = (object->local_got_offset(r_sym, GOT_TYPE_STANDARD)
7131ed0d50c3Schristos - got_base);
7132ed0d50c3Schristos }
7133ed0d50c3Schristos have_got_offset = true;
7134ed0d50c3Schristos break;
7135ed0d50c3Schristos
7136ed0d50c3Schristos default:
7137ed0d50c3Schristos break;
7138ed0d50c3Schristos }
7139ed0d50c3Schristos
7140ed0d50c3Schristos typename Reloc::Status reloc_status = Reloc::STATUS_OKAY;
7141ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr value;
7142ed0d50c3Schristos switch (r_type)
7143ed0d50c3Schristos {
7144ed0d50c3Schristos case elfcpp::R_AARCH64_NONE:
7145ed0d50c3Schristos break;
7146ed0d50c3Schristos
7147ed0d50c3Schristos case elfcpp::R_AARCH64_ABS64:
7148ed0d50c3Schristos if (!parameters->options().apply_dynamic_relocs()
7149ed0d50c3Schristos && parameters->options().output_is_position_independent()
7150ed0d50c3Schristos && gsym != NULL
7151ed0d50c3Schristos && gsym->needs_dynamic_reloc(reloc_property->reference_flags())
7152ed0d50c3Schristos && !gsym->can_use_relative_reloc(false))
7153ed0d50c3Schristos // We have generated an absolute dynamic relocation, so do not
7154ed0d50c3Schristos // apply the relocation statically. (Works around bugs in older
7155ed0d50c3Schristos // Android dynamic linkers.)
7156ed0d50c3Schristos break;
7157ed0d50c3Schristos reloc_status = Reloc::template rela_ua<64>(
7158ed0d50c3Schristos view, object, psymval, addend, reloc_property);
7159ed0d50c3Schristos break;
7160ed0d50c3Schristos
7161ed0d50c3Schristos case elfcpp::R_AARCH64_ABS32:
7162ed0d50c3Schristos if (!parameters->options().apply_dynamic_relocs()
7163ed0d50c3Schristos && parameters->options().output_is_position_independent()
7164ed0d50c3Schristos && gsym != NULL
7165ed0d50c3Schristos && gsym->needs_dynamic_reloc(reloc_property->reference_flags()))
7166ed0d50c3Schristos // We have generated an absolute dynamic relocation, so do not
7167ed0d50c3Schristos // apply the relocation statically. (Works around bugs in older
7168ed0d50c3Schristos // Android dynamic linkers.)
7169ed0d50c3Schristos break;
7170ed0d50c3Schristos reloc_status = Reloc::template rela_ua<32>(
7171ed0d50c3Schristos view, object, psymval, addend, reloc_property);
7172ed0d50c3Schristos break;
7173ed0d50c3Schristos
7174ed0d50c3Schristos case elfcpp::R_AARCH64_ABS16:
7175ed0d50c3Schristos if (!parameters->options().apply_dynamic_relocs()
7176ed0d50c3Schristos && parameters->options().output_is_position_independent()
7177ed0d50c3Schristos && gsym != NULL
7178ed0d50c3Schristos && gsym->needs_dynamic_reloc(reloc_property->reference_flags()))
7179ed0d50c3Schristos // We have generated an absolute dynamic relocation, so do not
7180ed0d50c3Schristos // apply the relocation statically. (Works around bugs in older
7181ed0d50c3Schristos // Android dynamic linkers.)
7182ed0d50c3Schristos break;
7183ed0d50c3Schristos reloc_status = Reloc::template rela_ua<16>(
7184ed0d50c3Schristos view, object, psymval, addend, reloc_property);
7185ed0d50c3Schristos break;
7186ed0d50c3Schristos
7187ed0d50c3Schristos case elfcpp::R_AARCH64_PREL64:
7188ed0d50c3Schristos reloc_status = Reloc::template pcrela_ua<64>(
7189ed0d50c3Schristos view, object, psymval, addend, address, reloc_property);
7190ed0d50c3Schristos break;
7191ed0d50c3Schristos
7192ed0d50c3Schristos case elfcpp::R_AARCH64_PREL32:
7193ed0d50c3Schristos reloc_status = Reloc::template pcrela_ua<32>(
7194ed0d50c3Schristos view, object, psymval, addend, address, reloc_property);
7195ed0d50c3Schristos break;
7196ed0d50c3Schristos
7197ed0d50c3Schristos case elfcpp::R_AARCH64_PREL16:
7198ed0d50c3Schristos reloc_status = Reloc::template pcrela_ua<16>(
7199ed0d50c3Schristos view, object, psymval, addend, address, reloc_property);
7200ed0d50c3Schristos break;
7201ed0d50c3Schristos
720206324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G0:
720306324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G0_NC:
720406324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G1:
720506324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G1_NC:
720606324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G2:
720706324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G2_NC:
720806324dcfSchristos case elfcpp::R_AARCH64_MOVW_UABS_G3:
720906324dcfSchristos reloc_status = Reloc::template rela_general<32>(
721006324dcfSchristos view, object, psymval, addend, reloc_property);
721106324dcfSchristos break;
721206324dcfSchristos case elfcpp::R_AARCH64_MOVW_SABS_G0:
721306324dcfSchristos case elfcpp::R_AARCH64_MOVW_SABS_G1:
721406324dcfSchristos case elfcpp::R_AARCH64_MOVW_SABS_G2:
721506324dcfSchristos reloc_status = Reloc::movnz(view, psymval->value(object, addend),
721606324dcfSchristos reloc_property);
721706324dcfSchristos break;
721806324dcfSchristos
7219ed0d50c3Schristos case elfcpp::R_AARCH64_LD_PREL_LO19:
7220ed0d50c3Schristos reloc_status = Reloc::template pcrela_general<32>(
7221ed0d50c3Schristos view, object, psymval, addend, address, reloc_property);
7222ed0d50c3Schristos break;
7223ed0d50c3Schristos
7224ed0d50c3Schristos case elfcpp::R_AARCH64_ADR_PREL_LO21:
7225ed0d50c3Schristos reloc_status = Reloc::adr(view, object, psymval, addend,
7226ed0d50c3Schristos address, reloc_property);
7227ed0d50c3Schristos break;
7228ed0d50c3Schristos
7229ed0d50c3Schristos case elfcpp::R_AARCH64_ADR_PREL_PG_HI21_NC:
7230ed0d50c3Schristos case elfcpp::R_AARCH64_ADR_PREL_PG_HI21:
7231ed0d50c3Schristos reloc_status = Reloc::adrp(view, object, psymval, addend, address,
7232ed0d50c3Schristos reloc_property);
7233ed0d50c3Schristos break;
7234ed0d50c3Schristos
7235ed0d50c3Schristos case elfcpp::R_AARCH64_LDST8_ABS_LO12_NC:
7236ed0d50c3Schristos case elfcpp::R_AARCH64_LDST16_ABS_LO12_NC:
7237ed0d50c3Schristos case elfcpp::R_AARCH64_LDST32_ABS_LO12_NC:
7238ed0d50c3Schristos case elfcpp::R_AARCH64_LDST64_ABS_LO12_NC:
7239ed0d50c3Schristos case elfcpp::R_AARCH64_LDST128_ABS_LO12_NC:
7240ed0d50c3Schristos case elfcpp::R_AARCH64_ADD_ABS_LO12_NC:
7241ed0d50c3Schristos reloc_status = Reloc::template rela_general<32>(
7242ed0d50c3Schristos view, object, psymval, addend, reloc_property);
7243ed0d50c3Schristos break;
7244ed0d50c3Schristos
7245ed0d50c3Schristos case elfcpp::R_AARCH64_CALL26:
7246ed0d50c3Schristos if (this->skip_call_tls_get_addr_)
7247ed0d50c3Schristos {
7248ed0d50c3Schristos // Double check that the TLSGD insn has been optimized away.
7249ed0d50c3Schristos typedef typename elfcpp::Swap<32, big_endian>::Valtype Insntype;
7250ed0d50c3Schristos Insntype insn = elfcpp::Swap<32, big_endian>::readval(
7251ed0d50c3Schristos reinterpret_cast<Insntype*>(view));
7252ed0d50c3Schristos gold_assert((insn & 0xff000000) == 0x91000000);
7253ed0d50c3Schristos
7254ed0d50c3Schristos reloc_status = Reloc::STATUS_OKAY;
7255ed0d50c3Schristos this->skip_call_tls_get_addr_ = false;
7256ed0d50c3Schristos // Return false to stop further processing this reloc.
7257ed0d50c3Schristos return false;
7258ed0d50c3Schristos }
725906324dcfSchristos // Fall through.
7260ed0d50c3Schristos case elfcpp::R_AARCH64_JUMP26:
7261ed0d50c3Schristos if (Reloc::maybe_apply_stub(r_type, relinfo, rela, view, address,
7262ed0d50c3Schristos gsym, psymval, object,
7263ed0d50c3Schristos target->stub_group_size_))
7264ed0d50c3Schristos break;
726506324dcfSchristos // Fall through.
7266ed0d50c3Schristos case elfcpp::R_AARCH64_TSTBR14:
7267ed0d50c3Schristos case elfcpp::R_AARCH64_CONDBR19:
7268ed0d50c3Schristos reloc_status = Reloc::template pcrela_general<32>(
7269ed0d50c3Schristos view, object, psymval, addend, address, reloc_property);
7270ed0d50c3Schristos break;
7271ed0d50c3Schristos
7272ed0d50c3Schristos case elfcpp::R_AARCH64_ADR_GOT_PAGE:
7273ed0d50c3Schristos gold_assert(have_got_offset);
7274ed0d50c3Schristos value = target->got_->address() + got_base + got_offset;
7275ed0d50c3Schristos reloc_status = Reloc::adrp(view, value + addend, address);
7276ed0d50c3Schristos break;
7277ed0d50c3Schristos
7278ed0d50c3Schristos case elfcpp::R_AARCH64_LD64_GOT_LO12_NC:
7279ed0d50c3Schristos gold_assert(have_got_offset);
7280ed0d50c3Schristos value = target->got_->address() + got_base + got_offset;
7281ed0d50c3Schristos reloc_status = Reloc::template rela_general<32>(
7282ed0d50c3Schristos view, value, addend, reloc_property);
7283ed0d50c3Schristos break;
7284ed0d50c3Schristos
7285ed0d50c3Schristos case elfcpp::R_AARCH64_LD64_GOTPAGE_LO15:
7286ed0d50c3Schristos {
7287ed0d50c3Schristos gold_assert(have_got_offset);
7288ed0d50c3Schristos value = target->got_->address() + got_base + got_offset + addend -
7289ed0d50c3Schristos Reloc::Page(target->got_->address() + got_base);
7290ed0d50c3Schristos if ((value & 7) != 0)
7291ed0d50c3Schristos reloc_status = Reloc::STATUS_OVERFLOW;
7292ed0d50c3Schristos else
7293ed0d50c3Schristos reloc_status = Reloc::template reloc_common<32>(
7294ed0d50c3Schristos view, value, reloc_property);
7295ed0d50c3Schristos break;
7296ed0d50c3Schristos }
7297ed0d50c3Schristos
7298ed0d50c3Schristos case elfcpp::R_AARCH64_TLSGD_ADR_PAGE21:
7299ed0d50c3Schristos case elfcpp::R_AARCH64_TLSGD_ADD_LO12_NC:
7300ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADR_PAGE21:
7301ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_LO12_NC:
7302ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G1:
7303ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC:
7304ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_HI12:
7305ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC:
7306ed0d50c3Schristos case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
7307ed0d50c3Schristos case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
7308ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G2:
7309ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G1:
7310ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
7311ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G0:
7312ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
7313ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12:
7314ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12:
7315ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
731606324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12:
731706324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
731806324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12:
731906324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
732006324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12:
732106324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
732206324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12:
732306324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
7324ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADR_PAGE21:
7325ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_LD64_LO12:
7326ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADD_LO12:
7327ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_CALL:
7328ed0d50c3Schristos reloc_status = relocate_tls(relinfo, target, relnum, rela, r_type,
7329ed0d50c3Schristos gsym, psymval, view, address);
7330ed0d50c3Schristos break;
7331ed0d50c3Schristos
7332ed0d50c3Schristos // These are dynamic relocations, which are unexpected when linking.
7333ed0d50c3Schristos case elfcpp::R_AARCH64_COPY:
7334ed0d50c3Schristos case elfcpp::R_AARCH64_GLOB_DAT:
7335ed0d50c3Schristos case elfcpp::R_AARCH64_JUMP_SLOT:
7336ed0d50c3Schristos case elfcpp::R_AARCH64_RELATIVE:
7337ed0d50c3Schristos case elfcpp::R_AARCH64_IRELATIVE:
7338ed0d50c3Schristos case elfcpp::R_AARCH64_TLS_DTPREL64:
7339ed0d50c3Schristos case elfcpp::R_AARCH64_TLS_DTPMOD64:
7340ed0d50c3Schristos case elfcpp::R_AARCH64_TLS_TPREL64:
7341ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC:
7342ed0d50c3Schristos gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
7343ed0d50c3Schristos _("unexpected reloc %u in object file"),
7344ed0d50c3Schristos r_type);
7345ed0d50c3Schristos break;
7346ed0d50c3Schristos
7347ed0d50c3Schristos default:
7348ed0d50c3Schristos gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
7349ed0d50c3Schristos _("unsupported reloc %s"),
7350ed0d50c3Schristos reloc_property->name().c_str());
7351ed0d50c3Schristos break;
7352ed0d50c3Schristos }
7353ed0d50c3Schristos
7354ed0d50c3Schristos // Report any errors.
7355ed0d50c3Schristos switch (reloc_status)
7356ed0d50c3Schristos {
7357ed0d50c3Schristos case Reloc::STATUS_OKAY:
7358ed0d50c3Schristos break;
7359ed0d50c3Schristos case Reloc::STATUS_OVERFLOW:
7360ed0d50c3Schristos gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
7361ed0d50c3Schristos _("relocation overflow in %s"),
7362ed0d50c3Schristos reloc_property->name().c_str());
7363ed0d50c3Schristos break;
7364ed0d50c3Schristos case Reloc::STATUS_BAD_RELOC:
7365ed0d50c3Schristos gold_error_at_location(
7366ed0d50c3Schristos relinfo,
7367ed0d50c3Schristos relnum,
7368ed0d50c3Schristos rela.get_r_offset(),
7369ed0d50c3Schristos _("unexpected opcode while processing relocation %s"),
7370ed0d50c3Schristos reloc_property->name().c_str());
7371ed0d50c3Schristos break;
7372ed0d50c3Schristos default:
7373ed0d50c3Schristos gold_unreachable();
7374ed0d50c3Schristos }
7375ed0d50c3Schristos
7376ed0d50c3Schristos return true;
7377ed0d50c3Schristos }
7378ed0d50c3Schristos
7379ed0d50c3Schristos
7380ed0d50c3Schristos template<int size, bool big_endian>
7381ed0d50c3Schristos inline
7382ed0d50c3Schristos typename AArch64_relocate_functions<size, big_endian>::Status
relocate_tls(const Relocate_info<size,big_endian> * relinfo,Target_aarch64<size,big_endian> * target,size_t relnum,const elfcpp::Rela<size,big_endian> & rela,unsigned int r_type,const Sized_symbol<size> * gsym,const Symbol_value<size> * psymval,unsigned char * view,typename elfcpp::Elf_types<size>::Elf_Addr address)7383ed0d50c3Schristos Target_aarch64<size, big_endian>::Relocate::relocate_tls(
7384ed0d50c3Schristos const Relocate_info<size, big_endian>* relinfo,
7385ed0d50c3Schristos Target_aarch64<size, big_endian>* target,
7386ed0d50c3Schristos size_t relnum,
7387ed0d50c3Schristos const elfcpp::Rela<size, big_endian>& rela,
7388ed0d50c3Schristos unsigned int r_type, const Sized_symbol<size>* gsym,
7389ed0d50c3Schristos const Symbol_value<size>* psymval,
7390ed0d50c3Schristos unsigned char* view,
7391ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr address)
7392ed0d50c3Schristos {
7393ed0d50c3Schristos typedef AArch64_relocate_functions<size, big_endian> aarch64_reloc_funcs;
7394ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
7395ed0d50c3Schristos
7396ed0d50c3Schristos Output_segment* tls_segment = relinfo->layout->tls_segment();
7397ed0d50c3Schristos const elfcpp::Elf_Xword addend = rela.get_r_addend();
7398ed0d50c3Schristos const AArch64_reloc_property* reloc_property =
7399ed0d50c3Schristos aarch64_reloc_property_table->get_reloc_property(r_type);
7400ed0d50c3Schristos gold_assert(reloc_property != NULL);
7401ed0d50c3Schristos
7402ed0d50c3Schristos const bool is_final = (gsym == NULL
7403ed0d50c3Schristos ? !parameters->options().shared()
7404ed0d50c3Schristos : gsym->final_value_is_known());
7405ed0d50c3Schristos tls::Tls_optimization tlsopt = Target_aarch64<size, big_endian>::
7406ed0d50c3Schristos optimize_tls_reloc(is_final, r_type);
7407ed0d50c3Schristos
7408ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object = relinfo->object;
7409ed0d50c3Schristos int tls_got_offset_type;
7410ed0d50c3Schristos switch (r_type)
7411ed0d50c3Schristos {
7412ed0d50c3Schristos case elfcpp::R_AARCH64_TLSGD_ADR_PAGE21:
7413ed0d50c3Schristos case elfcpp::R_AARCH64_TLSGD_ADD_LO12_NC: // Global-dynamic
7414ed0d50c3Schristos {
7415ed0d50c3Schristos if (tlsopt == tls::TLSOPT_TO_LE)
7416ed0d50c3Schristos {
7417ed0d50c3Schristos if (tls_segment == NULL)
7418ed0d50c3Schristos {
7419ed0d50c3Schristos gold_assert(parameters->errors()->error_count() > 0
7420ed0d50c3Schristos || issue_undefined_symbol_error(gsym));
7421ed0d50c3Schristos return aarch64_reloc_funcs::STATUS_BAD_RELOC;
7422ed0d50c3Schristos }
7423ed0d50c3Schristos return tls_gd_to_le(relinfo, target, rela, r_type, view,
7424ed0d50c3Schristos psymval);
7425ed0d50c3Schristos }
7426ed0d50c3Schristos else if (tlsopt == tls::TLSOPT_NONE)
7427ed0d50c3Schristos {
7428ed0d50c3Schristos tls_got_offset_type = GOT_TYPE_TLS_PAIR;
7429ed0d50c3Schristos // Firstly get the address for the got entry.
7430ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr got_entry_address;
7431ed0d50c3Schristos if (gsym != NULL)
7432ed0d50c3Schristos {
7433ed0d50c3Schristos gold_assert(gsym->has_got_offset(tls_got_offset_type));
7434ed0d50c3Schristos got_entry_address = target->got_->address() +
7435ed0d50c3Schristos gsym->got_offset(tls_got_offset_type);
7436ed0d50c3Schristos }
7437ed0d50c3Schristos else
7438ed0d50c3Schristos {
7439ed0d50c3Schristos unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
7440ed0d50c3Schristos gold_assert(
7441ed0d50c3Schristos object->local_has_got_offset(r_sym, tls_got_offset_type));
7442ed0d50c3Schristos got_entry_address = target->got_->address() +
7443ed0d50c3Schristos object->local_got_offset(r_sym, tls_got_offset_type);
7444ed0d50c3Schristos }
7445ed0d50c3Schristos
7446ed0d50c3Schristos // Relocate the address into adrp/ld, adrp/add pair.
7447ed0d50c3Schristos switch (r_type)
7448ed0d50c3Schristos {
7449ed0d50c3Schristos case elfcpp::R_AARCH64_TLSGD_ADR_PAGE21:
7450ed0d50c3Schristos return aarch64_reloc_funcs::adrp(
7451ed0d50c3Schristos view, got_entry_address + addend, address);
7452ed0d50c3Schristos
7453ed0d50c3Schristos break;
7454ed0d50c3Schristos
7455ed0d50c3Schristos case elfcpp::R_AARCH64_TLSGD_ADD_LO12_NC:
7456ed0d50c3Schristos return aarch64_reloc_funcs::template rela_general<32>(
7457ed0d50c3Schristos view, got_entry_address, addend, reloc_property);
7458ed0d50c3Schristos break;
7459ed0d50c3Schristos
7460ed0d50c3Schristos default:
7461ed0d50c3Schristos gold_unreachable();
7462ed0d50c3Schristos }
7463ed0d50c3Schristos }
7464ed0d50c3Schristos gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
7465ed0d50c3Schristos _("unsupported gd_to_ie relaxation on %u"),
7466ed0d50c3Schristos r_type);
7467ed0d50c3Schristos }
7468ed0d50c3Schristos break;
7469ed0d50c3Schristos
7470ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADR_PAGE21:
7471ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_LO12_NC: // Local-dynamic
7472ed0d50c3Schristos {
7473ed0d50c3Schristos if (tlsopt == tls::TLSOPT_TO_LE)
7474ed0d50c3Schristos {
7475ed0d50c3Schristos if (tls_segment == NULL)
7476ed0d50c3Schristos {
7477ed0d50c3Schristos gold_assert(parameters->errors()->error_count() > 0
7478ed0d50c3Schristos || issue_undefined_symbol_error(gsym));
7479ed0d50c3Schristos return aarch64_reloc_funcs::STATUS_BAD_RELOC;
7480ed0d50c3Schristos }
7481ed0d50c3Schristos return this->tls_ld_to_le(relinfo, target, rela, r_type, view,
7482ed0d50c3Schristos psymval);
7483ed0d50c3Schristos }
7484ed0d50c3Schristos
7485ed0d50c3Schristos gold_assert(tlsopt == tls::TLSOPT_NONE);
7486ed0d50c3Schristos // Relocate the field with the offset of the GOT entry for
7487ed0d50c3Schristos // the module index.
7488ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr got_entry_address;
7489ed0d50c3Schristos got_entry_address = (target->got_mod_index_entry(NULL, NULL, NULL) +
7490ed0d50c3Schristos target->got_->address());
7491ed0d50c3Schristos
7492ed0d50c3Schristos switch (r_type)
7493ed0d50c3Schristos {
7494ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADR_PAGE21:
7495ed0d50c3Schristos return aarch64_reloc_funcs::adrp(
7496ed0d50c3Schristos view, got_entry_address + addend, address);
7497ed0d50c3Schristos break;
7498ed0d50c3Schristos
7499ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_LO12_NC:
7500ed0d50c3Schristos return aarch64_reloc_funcs::template rela_general<32>(
7501ed0d50c3Schristos view, got_entry_address, addend, reloc_property);
7502ed0d50c3Schristos break;
7503ed0d50c3Schristos
7504ed0d50c3Schristos default:
7505ed0d50c3Schristos gold_unreachable();
7506ed0d50c3Schristos }
7507ed0d50c3Schristos }
7508ed0d50c3Schristos break;
7509ed0d50c3Schristos
7510ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G1:
7511ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC:
7512ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_HI12:
7513ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: // Other local-dynamic
7514ed0d50c3Schristos {
7515ed0d50c3Schristos AArch64_address value = psymval->value(object, 0);
7516ed0d50c3Schristos if (tlsopt == tls::TLSOPT_TO_LE)
7517ed0d50c3Schristos {
7518ed0d50c3Schristos if (tls_segment == NULL)
7519ed0d50c3Schristos {
7520ed0d50c3Schristos gold_assert(parameters->errors()->error_count() > 0
7521ed0d50c3Schristos || issue_undefined_symbol_error(gsym));
7522ed0d50c3Schristos return aarch64_reloc_funcs::STATUS_BAD_RELOC;
7523ed0d50c3Schristos }
7524ed0d50c3Schristos }
7525ed0d50c3Schristos switch (r_type)
7526ed0d50c3Schristos {
7527ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G1:
7528ed0d50c3Schristos return aarch64_reloc_funcs::movnz(view, value + addend,
7529ed0d50c3Schristos reloc_property);
7530ed0d50c3Schristos break;
7531ed0d50c3Schristos
7532ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC:
7533ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_HI12:
7534ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC:
7535ed0d50c3Schristos return aarch64_reloc_funcs::template rela_general<32>(
7536ed0d50c3Schristos view, value, addend, reloc_property);
7537ed0d50c3Schristos break;
7538ed0d50c3Schristos
7539ed0d50c3Schristos default:
7540ed0d50c3Schristos gold_unreachable();
7541ed0d50c3Schristos }
7542ed0d50c3Schristos // We should never reach here.
7543ed0d50c3Schristos }
7544ed0d50c3Schristos break;
7545ed0d50c3Schristos
7546ed0d50c3Schristos case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
7547ed0d50c3Schristos case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: // Initial-exec
7548ed0d50c3Schristos {
7549ed0d50c3Schristos if (tlsopt == tls::TLSOPT_TO_LE)
7550ed0d50c3Schristos {
7551ed0d50c3Schristos if (tls_segment == NULL)
7552ed0d50c3Schristos {
7553ed0d50c3Schristos gold_assert(parameters->errors()->error_count() > 0
7554ed0d50c3Schristos || issue_undefined_symbol_error(gsym));
7555ed0d50c3Schristos return aarch64_reloc_funcs::STATUS_BAD_RELOC;
7556ed0d50c3Schristos }
7557ed0d50c3Schristos return tls_ie_to_le(relinfo, target, rela, r_type, view,
7558ed0d50c3Schristos psymval);
7559ed0d50c3Schristos }
7560ed0d50c3Schristos tls_got_offset_type = GOT_TYPE_TLS_OFFSET;
7561ed0d50c3Schristos
7562ed0d50c3Schristos // Firstly get the address for the got entry.
7563ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr got_entry_address;
7564ed0d50c3Schristos if (gsym != NULL)
7565ed0d50c3Schristos {
7566ed0d50c3Schristos gold_assert(gsym->has_got_offset(tls_got_offset_type));
7567ed0d50c3Schristos got_entry_address = target->got_->address() +
7568ed0d50c3Schristos gsym->got_offset(tls_got_offset_type);
7569ed0d50c3Schristos }
7570ed0d50c3Schristos else
7571ed0d50c3Schristos {
7572ed0d50c3Schristos unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
7573ed0d50c3Schristos gold_assert(
7574ed0d50c3Schristos object->local_has_got_offset(r_sym, tls_got_offset_type));
7575ed0d50c3Schristos got_entry_address = target->got_->address() +
7576ed0d50c3Schristos object->local_got_offset(r_sym, tls_got_offset_type);
7577ed0d50c3Schristos }
7578ed0d50c3Schristos // Relocate the address into adrp/ld, adrp/add pair.
7579ed0d50c3Schristos switch (r_type)
7580ed0d50c3Schristos {
7581ed0d50c3Schristos case elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
7582ed0d50c3Schristos return aarch64_reloc_funcs::adrp(view, got_entry_address + addend,
7583ed0d50c3Schristos address);
7584ed0d50c3Schristos break;
7585ed0d50c3Schristos case elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
7586ed0d50c3Schristos return aarch64_reloc_funcs::template rela_general<32>(
7587ed0d50c3Schristos view, got_entry_address, addend, reloc_property);
7588ed0d50c3Schristos default:
7589ed0d50c3Schristos gold_unreachable();
7590ed0d50c3Schristos }
7591ed0d50c3Schristos }
7592ed0d50c3Schristos // We shall never reach here.
7593ed0d50c3Schristos break;
7594ed0d50c3Schristos
7595ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G2:
7596ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G1:
7597ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
7598ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G0:
7599ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
7600ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12:
7601ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12:
7602ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
760306324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12:
760406324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
760506324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12:
760606324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
760706324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12:
760806324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
760906324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12:
761006324dcfSchristos case elfcpp::R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
7611ed0d50c3Schristos {
7612ed0d50c3Schristos gold_assert(tls_segment != NULL);
7613ed0d50c3Schristos AArch64_address value = psymval->value(object, 0);
7614ed0d50c3Schristos
7615ed0d50c3Schristos if (!parameters->options().shared())
7616ed0d50c3Schristos {
7617ed0d50c3Schristos AArch64_address aligned_tcb_size =
7618ed0d50c3Schristos align_address(target->tcb_size(),
7619ed0d50c3Schristos tls_segment->maximum_alignment());
7620ed0d50c3Schristos value += aligned_tcb_size;
7621ed0d50c3Schristos switch (r_type)
7622ed0d50c3Schristos {
7623ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G2:
7624ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G1:
7625ed0d50c3Schristos case elfcpp::R_AARCH64_TLSLE_MOVW_TPREL_G0:
7626ed0d50c3Schristos return aarch64_reloc_funcs::movnz(view, value + addend,
7627ed0d50c3Schristos reloc_property);
7628ed0d50c3Schristos default:
7629ed0d50c3Schristos return aarch64_reloc_funcs::template
7630ed0d50c3Schristos rela_general<32>(view,
7631ed0d50c3Schristos value,
7632ed0d50c3Schristos addend,
7633ed0d50c3Schristos reloc_property);
7634ed0d50c3Schristos }
7635ed0d50c3Schristos }
7636ed0d50c3Schristos else
7637ed0d50c3Schristos gold_error(_("%s: unsupported reloc %u "
7638ed0d50c3Schristos "in non-static TLSLE mode."),
7639ed0d50c3Schristos object->name().c_str(), r_type);
7640ed0d50c3Schristos }
7641ed0d50c3Schristos break;
7642ed0d50c3Schristos
7643ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADR_PAGE21:
7644ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_LD64_LO12:
7645ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADD_LO12:
7646ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_CALL:
7647ed0d50c3Schristos {
7648ed0d50c3Schristos if (tlsopt == tls::TLSOPT_TO_LE)
7649ed0d50c3Schristos {
7650ed0d50c3Schristos if (tls_segment == NULL)
7651ed0d50c3Schristos {
7652ed0d50c3Schristos gold_assert(parameters->errors()->error_count() > 0
7653ed0d50c3Schristos || issue_undefined_symbol_error(gsym));
7654ed0d50c3Schristos return aarch64_reloc_funcs::STATUS_BAD_RELOC;
7655ed0d50c3Schristos }
7656ed0d50c3Schristos return tls_desc_gd_to_le(relinfo, target, rela, r_type,
7657ed0d50c3Schristos view, psymval);
7658ed0d50c3Schristos }
7659ed0d50c3Schristos else
7660ed0d50c3Schristos {
7661ed0d50c3Schristos tls_got_offset_type = (tlsopt == tls::TLSOPT_TO_IE
7662ed0d50c3Schristos ? GOT_TYPE_TLS_OFFSET
7663ed0d50c3Schristos : GOT_TYPE_TLS_DESC);
766406324dcfSchristos int got_tlsdesc_offset = 0;
7665ed0d50c3Schristos if (r_type != elfcpp::R_AARCH64_TLSDESC_CALL
7666ed0d50c3Schristos && tlsopt == tls::TLSOPT_NONE)
7667ed0d50c3Schristos {
7668ed0d50c3Schristos // We created GOT entries in the .got.tlsdesc portion of the
7669ed0d50c3Schristos // .got.plt section, but the offset stored in the symbol is the
7670ed0d50c3Schristos // offset within .got.tlsdesc.
767106324dcfSchristos got_tlsdesc_offset = (target->got_tlsdesc_->address()
767206324dcfSchristos - target->got_->address());
7673ed0d50c3Schristos }
7674ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr got_entry_address;
7675ed0d50c3Schristos if (gsym != NULL)
7676ed0d50c3Schristos {
7677ed0d50c3Schristos gold_assert(gsym->has_got_offset(tls_got_offset_type));
7678ed0d50c3Schristos got_entry_address = target->got_->address()
7679ed0d50c3Schristos + got_tlsdesc_offset
7680ed0d50c3Schristos + gsym->got_offset(tls_got_offset_type);
7681ed0d50c3Schristos }
7682ed0d50c3Schristos else
7683ed0d50c3Schristos {
7684ed0d50c3Schristos unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
7685ed0d50c3Schristos gold_assert(
7686ed0d50c3Schristos object->local_has_got_offset(r_sym, tls_got_offset_type));
7687ed0d50c3Schristos got_entry_address = target->got_->address() +
7688ed0d50c3Schristos got_tlsdesc_offset +
7689ed0d50c3Schristos object->local_got_offset(r_sym, tls_got_offset_type);
7690ed0d50c3Schristos }
7691ed0d50c3Schristos if (tlsopt == tls::TLSOPT_TO_IE)
7692ed0d50c3Schristos {
7693ed0d50c3Schristos return tls_desc_gd_to_ie(relinfo, target, rela, r_type,
7694ed0d50c3Schristos view, psymval, got_entry_address,
7695ed0d50c3Schristos address);
7696ed0d50c3Schristos }
7697ed0d50c3Schristos
7698ed0d50c3Schristos // Now do tlsdesc relocation.
7699ed0d50c3Schristos switch (r_type)
7700ed0d50c3Schristos {
7701ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADR_PAGE21:
7702ed0d50c3Schristos return aarch64_reloc_funcs::adrp(view,
7703ed0d50c3Schristos got_entry_address + addend,
7704ed0d50c3Schristos address);
7705ed0d50c3Schristos break;
7706ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_LD64_LO12:
7707ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADD_LO12:
7708ed0d50c3Schristos return aarch64_reloc_funcs::template rela_general<32>(
7709ed0d50c3Schristos view, got_entry_address, addend, reloc_property);
7710ed0d50c3Schristos break;
7711ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_CALL:
7712ed0d50c3Schristos return aarch64_reloc_funcs::STATUS_OKAY;
7713ed0d50c3Schristos break;
7714ed0d50c3Schristos default:
7715ed0d50c3Schristos gold_unreachable();
7716ed0d50c3Schristos }
7717ed0d50c3Schristos }
7718ed0d50c3Schristos }
7719ed0d50c3Schristos break;
7720ed0d50c3Schristos
7721ed0d50c3Schristos default:
7722ed0d50c3Schristos gold_error(_("%s: unsupported TLS reloc %u."),
7723ed0d50c3Schristos object->name().c_str(), r_type);
7724ed0d50c3Schristos }
7725ed0d50c3Schristos return aarch64_reloc_funcs::STATUS_BAD_RELOC;
7726ed0d50c3Schristos } // End of relocate_tls.
7727ed0d50c3Schristos
7728ed0d50c3Schristos
7729ed0d50c3Schristos template<int size, bool big_endian>
7730ed0d50c3Schristos inline
7731ed0d50c3Schristos typename AArch64_relocate_functions<size, big_endian>::Status
tls_gd_to_le(const Relocate_info<size,big_endian> * relinfo,Target_aarch64<size,big_endian> * target,const elfcpp::Rela<size,big_endian> & rela,unsigned int r_type,unsigned char * view,const Symbol_value<size> * psymval)7732ed0d50c3Schristos Target_aarch64<size, big_endian>::Relocate::tls_gd_to_le(
7733ed0d50c3Schristos const Relocate_info<size, big_endian>* relinfo,
7734ed0d50c3Schristos Target_aarch64<size, big_endian>* target,
7735ed0d50c3Schristos const elfcpp::Rela<size, big_endian>& rela,
7736ed0d50c3Schristos unsigned int r_type,
7737ed0d50c3Schristos unsigned char* view,
7738ed0d50c3Schristos const Symbol_value<size>* psymval)
7739ed0d50c3Schristos {
7740ed0d50c3Schristos typedef AArch64_relocate_functions<size, big_endian> aarch64_reloc_funcs;
7741ed0d50c3Schristos typedef typename elfcpp::Swap<32, big_endian>::Valtype Insntype;
7742ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
7743ed0d50c3Schristos
7744ed0d50c3Schristos Insntype* ip = reinterpret_cast<Insntype*>(view);
7745ed0d50c3Schristos Insntype insn1 = elfcpp::Swap<32, big_endian>::readval(ip);
7746ed0d50c3Schristos Insntype insn2 = elfcpp::Swap<32, big_endian>::readval(ip + 1);
7747ed0d50c3Schristos Insntype insn3 = elfcpp::Swap<32, big_endian>::readval(ip + 2);
7748ed0d50c3Schristos
7749ed0d50c3Schristos if (r_type == elfcpp::R_AARCH64_TLSGD_ADD_LO12_NC)
7750ed0d50c3Schristos {
7751ed0d50c3Schristos // This is the 2nd relocs, optimization should already have been
7752ed0d50c3Schristos // done.
7753ed0d50c3Schristos gold_assert((insn1 & 0xfff00000) == 0x91400000);
7754ed0d50c3Schristos return aarch64_reloc_funcs::STATUS_OKAY;
7755ed0d50c3Schristos }
7756ed0d50c3Schristos
7757ed0d50c3Schristos // The original sequence is -
7758ed0d50c3Schristos // 90000000 adrp x0, 0 <main>
7759ed0d50c3Schristos // 91000000 add x0, x0, #0x0
7760ed0d50c3Schristos // 94000000 bl 0 <__tls_get_addr>
7761ed0d50c3Schristos // optimized to sequence -
7762ed0d50c3Schristos // d53bd040 mrs x0, tpidr_el0
7763ed0d50c3Schristos // 91400000 add x0, x0, #0x0, lsl #12
7764ed0d50c3Schristos // 91000000 add x0, x0, #0x0
7765ed0d50c3Schristos
7766ed0d50c3Schristos // Unlike tls_ie_to_le, we change the 3 insns in one function call when we
7767ed0d50c3Schristos // encounter the first relocation "R_AARCH64_TLSGD_ADR_PAGE21". Because we
7768ed0d50c3Schristos // have to change "bl tls_get_addr", which does not have a corresponding tls
7769ed0d50c3Schristos // relocation type. So before proceeding, we need to make sure compiler
7770ed0d50c3Schristos // does not change the sequence.
7771ed0d50c3Schristos if(!(insn1 == 0x90000000 // adrp x0,0
7772ed0d50c3Schristos && insn2 == 0x91000000 // add x0, x0, #0x0
7773ed0d50c3Schristos && insn3 == 0x94000000)) // bl 0
7774ed0d50c3Schristos {
7775ed0d50c3Schristos // Ideally we should give up gd_to_le relaxation and do gd access.
7776ed0d50c3Schristos // However the gd_to_le relaxation decision has been made early
7777ed0d50c3Schristos // in the scan stage, where we did not allocate any GOT entry for
7778ed0d50c3Schristos // this symbol. Therefore we have to exit and report error now.
7779ed0d50c3Schristos gold_error(_("unexpected reloc insn sequence while relaxing "
7780ed0d50c3Schristos "tls gd to le for reloc %u."), r_type);
7781ed0d50c3Schristos return aarch64_reloc_funcs::STATUS_BAD_RELOC;
7782ed0d50c3Schristos }
7783ed0d50c3Schristos
7784ed0d50c3Schristos // Write new insns.
7785ed0d50c3Schristos insn1 = 0xd53bd040; // mrs x0, tpidr_el0
7786ed0d50c3Schristos insn2 = 0x91400000; // add x0, x0, #0x0, lsl #12
7787ed0d50c3Schristos insn3 = 0x91000000; // add x0, x0, #0x0
7788ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(ip, insn1);
7789ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(ip + 1, insn2);
7790ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(ip + 2, insn3);
7791ed0d50c3Schristos
7792ed0d50c3Schristos // Calculate tprel value.
7793ed0d50c3Schristos Output_segment* tls_segment = relinfo->layout->tls_segment();
7794ed0d50c3Schristos gold_assert(tls_segment != NULL);
7795ed0d50c3Schristos AArch64_address value = psymval->value(relinfo->object, 0);
7796ed0d50c3Schristos const elfcpp::Elf_Xword addend = rela.get_r_addend();
7797ed0d50c3Schristos AArch64_address aligned_tcb_size =
7798ed0d50c3Schristos align_address(target->tcb_size(), tls_segment->maximum_alignment());
7799ed0d50c3Schristos AArch64_address x = value + aligned_tcb_size;
7800ed0d50c3Schristos
7801ed0d50c3Schristos // After new insns are written, apply TLSLE relocs.
7802ed0d50c3Schristos const AArch64_reloc_property* rp1 =
7803ed0d50c3Schristos aarch64_reloc_property_table->get_reloc_property(
7804ed0d50c3Schristos elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12);
7805ed0d50c3Schristos const AArch64_reloc_property* rp2 =
7806ed0d50c3Schristos aarch64_reloc_property_table->get_reloc_property(
7807ed0d50c3Schristos elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12);
7808ed0d50c3Schristos gold_assert(rp1 != NULL && rp2 != NULL);
7809ed0d50c3Schristos
7810ed0d50c3Schristos typename aarch64_reloc_funcs::Status s1 =
7811ed0d50c3Schristos aarch64_reloc_funcs::template rela_general<32>(view + 4,
7812ed0d50c3Schristos x,
7813ed0d50c3Schristos addend,
7814ed0d50c3Schristos rp1);
7815ed0d50c3Schristos if (s1 != aarch64_reloc_funcs::STATUS_OKAY)
7816ed0d50c3Schristos return s1;
7817ed0d50c3Schristos
7818ed0d50c3Schristos typename aarch64_reloc_funcs::Status s2 =
7819ed0d50c3Schristos aarch64_reloc_funcs::template rela_general<32>(view + 8,
7820ed0d50c3Schristos x,
7821ed0d50c3Schristos addend,
7822ed0d50c3Schristos rp2);
7823ed0d50c3Schristos
7824ed0d50c3Schristos this->skip_call_tls_get_addr_ = true;
7825ed0d50c3Schristos return s2;
7826ed0d50c3Schristos } // End of tls_gd_to_le
7827ed0d50c3Schristos
7828ed0d50c3Schristos
7829ed0d50c3Schristos template<int size, bool big_endian>
7830ed0d50c3Schristos inline
7831ed0d50c3Schristos typename AArch64_relocate_functions<size, big_endian>::Status
tls_ld_to_le(const Relocate_info<size,big_endian> * relinfo,Target_aarch64<size,big_endian> * target,const elfcpp::Rela<size,big_endian> & rela,unsigned int r_type,unsigned char * view,const Symbol_value<size> * psymval)7832ed0d50c3Schristos Target_aarch64<size, big_endian>::Relocate::tls_ld_to_le(
7833ed0d50c3Schristos const Relocate_info<size, big_endian>* relinfo,
7834ed0d50c3Schristos Target_aarch64<size, big_endian>* target,
7835ed0d50c3Schristos const elfcpp::Rela<size, big_endian>& rela,
7836ed0d50c3Schristos unsigned int r_type,
7837ed0d50c3Schristos unsigned char* view,
7838ed0d50c3Schristos const Symbol_value<size>* psymval)
7839ed0d50c3Schristos {
7840ed0d50c3Schristos typedef AArch64_relocate_functions<size, big_endian> aarch64_reloc_funcs;
7841ed0d50c3Schristos typedef typename elfcpp::Swap<32, big_endian>::Valtype Insntype;
7842ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
7843ed0d50c3Schristos
7844ed0d50c3Schristos Insntype* ip = reinterpret_cast<Insntype*>(view);
7845ed0d50c3Schristos Insntype insn1 = elfcpp::Swap<32, big_endian>::readval(ip);
7846ed0d50c3Schristos Insntype insn2 = elfcpp::Swap<32, big_endian>::readval(ip + 1);
7847ed0d50c3Schristos Insntype insn3 = elfcpp::Swap<32, big_endian>::readval(ip + 2);
7848ed0d50c3Schristos
7849ed0d50c3Schristos if (r_type == elfcpp::R_AARCH64_TLSLD_ADD_LO12_NC)
7850ed0d50c3Schristos {
7851ed0d50c3Schristos // This is the 2nd relocs, optimization should already have been
7852ed0d50c3Schristos // done.
7853ed0d50c3Schristos gold_assert((insn1 & 0xfff00000) == 0x91400000);
7854ed0d50c3Schristos return aarch64_reloc_funcs::STATUS_OKAY;
7855ed0d50c3Schristos }
7856ed0d50c3Schristos
7857ed0d50c3Schristos // The original sequence is -
7858ed0d50c3Schristos // 90000000 adrp x0, 0 <main>
7859ed0d50c3Schristos // 91000000 add x0, x0, #0x0
7860ed0d50c3Schristos // 94000000 bl 0 <__tls_get_addr>
7861ed0d50c3Schristos // optimized to sequence -
7862ed0d50c3Schristos // d53bd040 mrs x0, tpidr_el0
7863ed0d50c3Schristos // 91400000 add x0, x0, #0x0, lsl #12
7864ed0d50c3Schristos // 91000000 add x0, x0, #0x0
7865ed0d50c3Schristos
7866ed0d50c3Schristos // Unlike tls_ie_to_le, we change the 3 insns in one function call when we
7867ed0d50c3Schristos // encounter the first relocation "R_AARCH64_TLSLD_ADR_PAGE21". Because we
7868ed0d50c3Schristos // have to change "bl tls_get_addr", which does not have a corresponding tls
7869ed0d50c3Schristos // relocation type. So before proceeding, we need to make sure compiler
7870ed0d50c3Schristos // does not change the sequence.
7871ed0d50c3Schristos if(!(insn1 == 0x90000000 // adrp x0,0
7872ed0d50c3Schristos && insn2 == 0x91000000 // add x0, x0, #0x0
7873ed0d50c3Schristos && insn3 == 0x94000000)) // bl 0
7874ed0d50c3Schristos {
7875ed0d50c3Schristos // Ideally we should give up gd_to_le relaxation and do gd access.
7876ed0d50c3Schristos // However the gd_to_le relaxation decision has been made early
787706324dcfSchristos // in the scan stage, where we did not allocate a GOT entry for
787806324dcfSchristos // this symbol. Therefore we have to exit and report an error now.
7879ed0d50c3Schristos gold_error(_("unexpected reloc insn sequence while relaxing "
7880ed0d50c3Schristos "tls gd to le for reloc %u."), r_type);
7881ed0d50c3Schristos return aarch64_reloc_funcs::STATUS_BAD_RELOC;
7882ed0d50c3Schristos }
7883ed0d50c3Schristos
7884ed0d50c3Schristos // Write new insns.
7885ed0d50c3Schristos insn1 = 0xd53bd040; // mrs x0, tpidr_el0
7886ed0d50c3Schristos insn2 = 0x91400000; // add x0, x0, #0x0, lsl #12
7887ed0d50c3Schristos insn3 = 0x91000000; // add x0, x0, #0x0
7888ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(ip, insn1);
7889ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(ip + 1, insn2);
7890ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(ip + 2, insn3);
7891ed0d50c3Schristos
7892ed0d50c3Schristos // Calculate tprel value.
7893ed0d50c3Schristos Output_segment* tls_segment = relinfo->layout->tls_segment();
7894ed0d50c3Schristos gold_assert(tls_segment != NULL);
7895ed0d50c3Schristos AArch64_address value = psymval->value(relinfo->object, 0);
7896ed0d50c3Schristos const elfcpp::Elf_Xword addend = rela.get_r_addend();
7897ed0d50c3Schristos AArch64_address aligned_tcb_size =
7898ed0d50c3Schristos align_address(target->tcb_size(), tls_segment->maximum_alignment());
7899ed0d50c3Schristos AArch64_address x = value + aligned_tcb_size;
7900ed0d50c3Schristos
7901ed0d50c3Schristos // After new insns are written, apply TLSLE relocs.
7902ed0d50c3Schristos const AArch64_reloc_property* rp1 =
7903ed0d50c3Schristos aarch64_reloc_property_table->get_reloc_property(
7904ed0d50c3Schristos elfcpp::R_AARCH64_TLSLE_ADD_TPREL_HI12);
7905ed0d50c3Schristos const AArch64_reloc_property* rp2 =
7906ed0d50c3Schristos aarch64_reloc_property_table->get_reloc_property(
7907ed0d50c3Schristos elfcpp::R_AARCH64_TLSLE_ADD_TPREL_LO12);
7908ed0d50c3Schristos gold_assert(rp1 != NULL && rp2 != NULL);
7909ed0d50c3Schristos
7910ed0d50c3Schristos typename aarch64_reloc_funcs::Status s1 =
7911ed0d50c3Schristos aarch64_reloc_funcs::template rela_general<32>(view + 4,
7912ed0d50c3Schristos x,
7913ed0d50c3Schristos addend,
7914ed0d50c3Schristos rp1);
7915ed0d50c3Schristos if (s1 != aarch64_reloc_funcs::STATUS_OKAY)
7916ed0d50c3Schristos return s1;
7917ed0d50c3Schristos
7918ed0d50c3Schristos typename aarch64_reloc_funcs::Status s2 =
7919ed0d50c3Schristos aarch64_reloc_funcs::template rela_general<32>(view + 8,
7920ed0d50c3Schristos x,
7921ed0d50c3Schristos addend,
7922ed0d50c3Schristos rp2);
7923ed0d50c3Schristos
7924ed0d50c3Schristos this->skip_call_tls_get_addr_ = true;
7925ed0d50c3Schristos return s2;
7926ed0d50c3Schristos
7927ed0d50c3Schristos } // End of tls_ld_to_le
7928ed0d50c3Schristos
7929ed0d50c3Schristos template<int size, bool big_endian>
7930ed0d50c3Schristos inline
7931ed0d50c3Schristos typename AArch64_relocate_functions<size, big_endian>::Status
tls_ie_to_le(const Relocate_info<size,big_endian> * relinfo,Target_aarch64<size,big_endian> * target,const elfcpp::Rela<size,big_endian> & rela,unsigned int r_type,unsigned char * view,const Symbol_value<size> * psymval)7932ed0d50c3Schristos Target_aarch64<size, big_endian>::Relocate::tls_ie_to_le(
7933ed0d50c3Schristos const Relocate_info<size, big_endian>* relinfo,
7934ed0d50c3Schristos Target_aarch64<size, big_endian>* target,
7935ed0d50c3Schristos const elfcpp::Rela<size, big_endian>& rela,
7936ed0d50c3Schristos unsigned int r_type,
7937ed0d50c3Schristos unsigned char* view,
7938ed0d50c3Schristos const Symbol_value<size>* psymval)
7939ed0d50c3Schristos {
7940ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
7941ed0d50c3Schristos typedef typename elfcpp::Swap<32, big_endian>::Valtype Insntype;
7942ed0d50c3Schristos typedef AArch64_relocate_functions<size, big_endian> aarch64_reloc_funcs;
7943ed0d50c3Schristos
7944ed0d50c3Schristos AArch64_address value = psymval->value(relinfo->object, 0);
7945ed0d50c3Schristos Output_segment* tls_segment = relinfo->layout->tls_segment();
7946ed0d50c3Schristos AArch64_address aligned_tcb_address =
7947ed0d50c3Schristos align_address(target->tcb_size(), tls_segment->maximum_alignment());
7948ed0d50c3Schristos const elfcpp::Elf_Xword addend = rela.get_r_addend();
7949ed0d50c3Schristos AArch64_address x = value + addend + aligned_tcb_address;
7950ed0d50c3Schristos // "x" is the offset to tp, we can only do this if x is within
7951ed0d50c3Schristos // range [0, 2^32-1]
7952ed0d50c3Schristos if (!(size == 32 || (size == 64 && (static_cast<uint64_t>(x) >> 32) == 0)))
7953ed0d50c3Schristos {
7954ed0d50c3Schristos gold_error(_("TLS variable referred by reloc %u is too far from TP."),
7955ed0d50c3Schristos r_type);
7956ed0d50c3Schristos return aarch64_reloc_funcs::STATUS_BAD_RELOC;
7957ed0d50c3Schristos }
7958ed0d50c3Schristos
7959ed0d50c3Schristos Insntype* ip = reinterpret_cast<Insntype*>(view);
7960ed0d50c3Schristos Insntype insn = elfcpp::Swap<32, big_endian>::readval(ip);
7961ed0d50c3Schristos unsigned int regno;
7962ed0d50c3Schristos Insntype newinsn;
7963ed0d50c3Schristos if (r_type == elfcpp::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21)
7964ed0d50c3Schristos {
7965ed0d50c3Schristos // Generate movz.
7966ed0d50c3Schristos regno = (insn & 0x1f);
7967ed0d50c3Schristos newinsn = (0xd2a00000 | regno) | (((x >> 16) & 0xffff) << 5);
7968ed0d50c3Schristos }
7969ed0d50c3Schristos else if (r_type == elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC)
7970ed0d50c3Schristos {
7971ed0d50c3Schristos // Generate movk.
7972ed0d50c3Schristos regno = (insn & 0x1f);
7973ed0d50c3Schristos gold_assert(regno == ((insn >> 5) & 0x1f));
7974ed0d50c3Schristos newinsn = (0xf2800000 | regno) | ((x & 0xffff) << 5);
7975ed0d50c3Schristos }
7976ed0d50c3Schristos else
7977ed0d50c3Schristos gold_unreachable();
7978ed0d50c3Schristos
7979ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(ip, newinsn);
7980ed0d50c3Schristos return aarch64_reloc_funcs::STATUS_OKAY;
7981ed0d50c3Schristos } // End of tls_ie_to_le
7982ed0d50c3Schristos
7983ed0d50c3Schristos
7984ed0d50c3Schristos template<int size, bool big_endian>
7985ed0d50c3Schristos inline
7986ed0d50c3Schristos typename AArch64_relocate_functions<size, big_endian>::Status
tls_desc_gd_to_le(const Relocate_info<size,big_endian> * relinfo,Target_aarch64<size,big_endian> * target,const elfcpp::Rela<size,big_endian> & rela,unsigned int r_type,unsigned char * view,const Symbol_value<size> * psymval)7987ed0d50c3Schristos Target_aarch64<size, big_endian>::Relocate::tls_desc_gd_to_le(
7988ed0d50c3Schristos const Relocate_info<size, big_endian>* relinfo,
7989ed0d50c3Schristos Target_aarch64<size, big_endian>* target,
7990ed0d50c3Schristos const elfcpp::Rela<size, big_endian>& rela,
7991ed0d50c3Schristos unsigned int r_type,
7992ed0d50c3Schristos unsigned char* view,
7993ed0d50c3Schristos const Symbol_value<size>* psymval)
7994ed0d50c3Schristos {
7995ed0d50c3Schristos typedef typename elfcpp::Elf_types<size>::Elf_Addr AArch64_address;
7996ed0d50c3Schristos typedef typename elfcpp::Swap<32, big_endian>::Valtype Insntype;
7997ed0d50c3Schristos typedef AArch64_relocate_functions<size, big_endian> aarch64_reloc_funcs;
7998ed0d50c3Schristos
7999ed0d50c3Schristos // TLSDESC-GD sequence is like:
8000ed0d50c3Schristos // adrp x0, :tlsdesc:v1
8001ed0d50c3Schristos // ldr x1, [x0, #:tlsdesc_lo12:v1]
8002ed0d50c3Schristos // add x0, x0, :tlsdesc_lo12:v1
8003ed0d50c3Schristos // .tlsdesccall v1
8004ed0d50c3Schristos // blr x1
8005ed0d50c3Schristos // After desc_gd_to_le optimization, the sequence will be like:
8006ed0d50c3Schristos // movz x0, #0x0, lsl #16
8007ed0d50c3Schristos // movk x0, #0x10
8008ed0d50c3Schristos // nop
8009ed0d50c3Schristos // nop
8010ed0d50c3Schristos
8011ed0d50c3Schristos // Calculate tprel value.
8012ed0d50c3Schristos Output_segment* tls_segment = relinfo->layout->tls_segment();
8013ed0d50c3Schristos gold_assert(tls_segment != NULL);
8014ed0d50c3Schristos Insntype* ip = reinterpret_cast<Insntype*>(view);
8015ed0d50c3Schristos const elfcpp::Elf_Xword addend = rela.get_r_addend();
8016ed0d50c3Schristos AArch64_address value = psymval->value(relinfo->object, addend);
8017ed0d50c3Schristos AArch64_address aligned_tcb_size =
8018ed0d50c3Schristos align_address(target->tcb_size(), tls_segment->maximum_alignment());
8019ed0d50c3Schristos AArch64_address x = value + aligned_tcb_size;
8020ed0d50c3Schristos // x is the offset to tp, we can only do this if x is within range
8021ed0d50c3Schristos // [0, 2^32-1]. If x is out of range, fail and exit.
8022ed0d50c3Schristos if (size == 64 && (static_cast<uint64_t>(x) >> 32) != 0)
8023ed0d50c3Schristos {
8024ed0d50c3Schristos gold_error(_("TLS variable referred by reloc %u is too far from TP. "
8025ed0d50c3Schristos "We Can't do gd_to_le relaxation.\n"), r_type);
8026ed0d50c3Schristos return aarch64_reloc_funcs::STATUS_BAD_RELOC;
8027ed0d50c3Schristos }
8028ed0d50c3Schristos Insntype newinsn;
8029ed0d50c3Schristos switch (r_type)
8030ed0d50c3Schristos {
8031ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADD_LO12:
8032ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_CALL:
8033ed0d50c3Schristos // Change to nop
8034ed0d50c3Schristos newinsn = 0xd503201f;
8035ed0d50c3Schristos break;
8036ed0d50c3Schristos
8037ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADR_PAGE21:
8038ed0d50c3Schristos // Change to movz.
8039ed0d50c3Schristos newinsn = 0xd2a00000 | (((x >> 16) & 0xffff) << 5);
8040ed0d50c3Schristos break;
8041ed0d50c3Schristos
8042ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_LD64_LO12:
8043ed0d50c3Schristos // Change to movk.
8044ed0d50c3Schristos newinsn = 0xf2800000 | ((x & 0xffff) << 5);
8045ed0d50c3Schristos break;
8046ed0d50c3Schristos
8047ed0d50c3Schristos default:
8048ed0d50c3Schristos gold_error(_("unsupported tlsdesc gd_to_le optimization on reloc %u"),
8049ed0d50c3Schristos r_type);
8050ed0d50c3Schristos gold_unreachable();
8051ed0d50c3Schristos }
8052ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(ip, newinsn);
8053ed0d50c3Schristos return aarch64_reloc_funcs::STATUS_OKAY;
8054ed0d50c3Schristos } // End of tls_desc_gd_to_le
8055ed0d50c3Schristos
8056ed0d50c3Schristos
8057ed0d50c3Schristos template<int size, bool big_endian>
8058ed0d50c3Schristos inline
8059ed0d50c3Schristos typename AArch64_relocate_functions<size, big_endian>::Status
tls_desc_gd_to_ie(const Relocate_info<size,big_endian> *,Target_aarch64<size,big_endian> *,const elfcpp::Rela<size,big_endian> & rela,unsigned int r_type,unsigned char * view,const Symbol_value<size> *,typename elfcpp::Elf_types<size>::Elf_Addr got_entry_address,typename elfcpp::Elf_types<size>::Elf_Addr address)8060ed0d50c3Schristos Target_aarch64<size, big_endian>::Relocate::tls_desc_gd_to_ie(
8061ed0d50c3Schristos const Relocate_info<size, big_endian>* /* relinfo */,
8062ed0d50c3Schristos Target_aarch64<size, big_endian>* /* target */,
8063ed0d50c3Schristos const elfcpp::Rela<size, big_endian>& rela,
8064ed0d50c3Schristos unsigned int r_type,
8065ed0d50c3Schristos unsigned char* view,
8066ed0d50c3Schristos const Symbol_value<size>* /* psymval */,
8067ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr got_entry_address,
8068ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr address)
8069ed0d50c3Schristos {
8070ed0d50c3Schristos typedef typename elfcpp::Swap<32, big_endian>::Valtype Insntype;
8071ed0d50c3Schristos typedef AArch64_relocate_functions<size, big_endian> aarch64_reloc_funcs;
8072ed0d50c3Schristos
8073ed0d50c3Schristos // TLSDESC-GD sequence is like:
8074ed0d50c3Schristos // adrp x0, :tlsdesc:v1
8075ed0d50c3Schristos // ldr x1, [x0, #:tlsdesc_lo12:v1]
8076ed0d50c3Schristos // add x0, x0, :tlsdesc_lo12:v1
8077ed0d50c3Schristos // .tlsdesccall v1
8078ed0d50c3Schristos // blr x1
8079ed0d50c3Schristos // After desc_gd_to_ie optimization, the sequence will be like:
8080ed0d50c3Schristos // adrp x0, :tlsie:v1
8081ed0d50c3Schristos // ldr x0, [x0, :tlsie_lo12:v1]
8082ed0d50c3Schristos // nop
8083ed0d50c3Schristos // nop
8084ed0d50c3Schristos
8085ed0d50c3Schristos Insntype* ip = reinterpret_cast<Insntype*>(view);
8086ed0d50c3Schristos const elfcpp::Elf_Xword addend = rela.get_r_addend();
8087ed0d50c3Schristos Insntype newinsn;
8088ed0d50c3Schristos switch (r_type)
8089ed0d50c3Schristos {
8090ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADD_LO12:
8091ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_CALL:
8092ed0d50c3Schristos // Change to nop
8093ed0d50c3Schristos newinsn = 0xd503201f;
8094ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(ip, newinsn);
8095ed0d50c3Schristos break;
8096ed0d50c3Schristos
8097ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_ADR_PAGE21:
8098ed0d50c3Schristos {
8099ed0d50c3Schristos return aarch64_reloc_funcs::adrp(view, got_entry_address + addend,
8100ed0d50c3Schristos address);
8101ed0d50c3Schristos }
8102ed0d50c3Schristos break;
8103ed0d50c3Schristos
8104ed0d50c3Schristos case elfcpp::R_AARCH64_TLSDESC_LD64_LO12:
8105ed0d50c3Schristos {
8106ed0d50c3Schristos // Set ldr target register to be x0.
8107ed0d50c3Schristos Insntype insn = elfcpp::Swap<32, big_endian>::readval(ip);
8108ed0d50c3Schristos insn &= 0xffffffe0;
8109ed0d50c3Schristos elfcpp::Swap<32, big_endian>::writeval(ip, insn);
8110ed0d50c3Schristos // Do relocation.
8111ed0d50c3Schristos const AArch64_reloc_property* reloc_property =
8112ed0d50c3Schristos aarch64_reloc_property_table->get_reloc_property(
8113ed0d50c3Schristos elfcpp::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC);
8114ed0d50c3Schristos return aarch64_reloc_funcs::template rela_general<32>(
8115ed0d50c3Schristos view, got_entry_address, addend, reloc_property);
8116ed0d50c3Schristos }
8117ed0d50c3Schristos break;
8118ed0d50c3Schristos
8119ed0d50c3Schristos default:
8120ed0d50c3Schristos gold_error(_("Don't support tlsdesc gd_to_ie optimization on reloc %u"),
8121ed0d50c3Schristos r_type);
8122ed0d50c3Schristos gold_unreachable();
8123ed0d50c3Schristos }
8124ed0d50c3Schristos return aarch64_reloc_funcs::STATUS_OKAY;
8125ed0d50c3Schristos } // End of tls_desc_gd_to_ie
8126ed0d50c3Schristos
8127ed0d50c3Schristos // Relocate section data.
8128ed0d50c3Schristos
8129ed0d50c3Schristos template<int size, bool big_endian>
8130ed0d50c3Schristos void
relocate_section(const Relocate_info<size,big_endian> * relinfo,unsigned int sh_type,const unsigned char * prelocs,size_t reloc_count,Output_section * output_section,bool needs_special_offset_handling,unsigned char * view,typename elfcpp::Elf_types<size>::Elf_Addr address,section_size_type view_size,const Reloc_symbol_changes * reloc_symbol_changes)8131ed0d50c3Schristos Target_aarch64<size, big_endian>::relocate_section(
8132ed0d50c3Schristos const Relocate_info<size, big_endian>* relinfo,
8133ed0d50c3Schristos unsigned int sh_type,
8134ed0d50c3Schristos const unsigned char* prelocs,
8135ed0d50c3Schristos size_t reloc_count,
8136ed0d50c3Schristos Output_section* output_section,
8137ed0d50c3Schristos bool needs_special_offset_handling,
8138ed0d50c3Schristos unsigned char* view,
8139ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr address,
8140ed0d50c3Schristos section_size_type view_size,
8141ed0d50c3Schristos const Reloc_symbol_changes* reloc_symbol_changes)
8142ed0d50c3Schristos {
814306324dcfSchristos typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
8144ed0d50c3Schristos typedef Target_aarch64<size, big_endian> Aarch64;
8145ed0d50c3Schristos typedef typename Target_aarch64<size, big_endian>::Relocate AArch64_relocate;
8146ed0d50c3Schristos typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
8147ed0d50c3Schristos Classify_reloc;
8148ed0d50c3Schristos
8149ed0d50c3Schristos gold_assert(sh_type == elfcpp::SHT_RELA);
8150ed0d50c3Schristos
815106324dcfSchristos // See if we are relocating a relaxed input section. If so, the view
815206324dcfSchristos // covers the whole output section and we need to adjust accordingly.
815306324dcfSchristos if (needs_special_offset_handling)
815406324dcfSchristos {
815506324dcfSchristos const Output_relaxed_input_section* poris =
815606324dcfSchristos output_section->find_relaxed_input_section(relinfo->object,
815706324dcfSchristos relinfo->data_shndx);
815806324dcfSchristos if (poris != NULL)
815906324dcfSchristos {
816006324dcfSchristos Address section_address = poris->address();
816106324dcfSchristos section_size_type section_size = poris->data_size();
816206324dcfSchristos
816306324dcfSchristos gold_assert((section_address >= address)
816406324dcfSchristos && ((section_address + section_size)
816506324dcfSchristos <= (address + view_size)));
816606324dcfSchristos
816706324dcfSchristos off_t offset = section_address - address;
816806324dcfSchristos view += offset;
816906324dcfSchristos address += offset;
817006324dcfSchristos view_size = section_size;
817106324dcfSchristos }
817206324dcfSchristos }
817306324dcfSchristos
8174ed0d50c3Schristos gold::relocate_section<size, big_endian, Aarch64, AArch64_relocate,
8175ed0d50c3Schristos gold::Default_comdat_behavior, Classify_reloc>(
8176ed0d50c3Schristos relinfo,
8177ed0d50c3Schristos this,
8178ed0d50c3Schristos prelocs,
8179ed0d50c3Schristos reloc_count,
8180ed0d50c3Schristos output_section,
8181ed0d50c3Schristos needs_special_offset_handling,
8182ed0d50c3Schristos view,
8183ed0d50c3Schristos address,
8184ed0d50c3Schristos view_size,
8185ed0d50c3Schristos reloc_symbol_changes);
8186ed0d50c3Schristos }
8187ed0d50c3Schristos
8188ed0d50c3Schristos // Scan the relocs during a relocatable link.
8189ed0d50c3Schristos
8190ed0d50c3Schristos template<int size, bool big_endian>
8191ed0d50c3Schristos void
scan_relocatable_relocs(Symbol_table * symtab,Layout * layout,Sized_relobj_file<size,big_endian> * object,unsigned int data_shndx,unsigned int sh_type,const unsigned char * prelocs,size_t reloc_count,Output_section * output_section,bool needs_special_offset_handling,size_t local_symbol_count,const unsigned char * plocal_symbols,Relocatable_relocs * rr)8192ed0d50c3Schristos Target_aarch64<size, big_endian>::scan_relocatable_relocs(
8193ed0d50c3Schristos Symbol_table* symtab,
8194ed0d50c3Schristos Layout* layout,
8195ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object,
8196ed0d50c3Schristos unsigned int data_shndx,
8197ed0d50c3Schristos unsigned int sh_type,
8198ed0d50c3Schristos const unsigned char* prelocs,
8199ed0d50c3Schristos size_t reloc_count,
8200ed0d50c3Schristos Output_section* output_section,
8201ed0d50c3Schristos bool needs_special_offset_handling,
8202ed0d50c3Schristos size_t local_symbol_count,
8203ed0d50c3Schristos const unsigned char* plocal_symbols,
8204ed0d50c3Schristos Relocatable_relocs* rr)
8205ed0d50c3Schristos {
8206ed0d50c3Schristos typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
8207ed0d50c3Schristos Classify_reloc;
8208ed0d50c3Schristos typedef gold::Default_scan_relocatable_relocs<Classify_reloc>
8209ed0d50c3Schristos Scan_relocatable_relocs;
8210ed0d50c3Schristos
8211ed0d50c3Schristos gold_assert(sh_type == elfcpp::SHT_RELA);
8212ed0d50c3Schristos
8213ed0d50c3Schristos gold::scan_relocatable_relocs<size, big_endian, Scan_relocatable_relocs>(
8214ed0d50c3Schristos symtab,
8215ed0d50c3Schristos layout,
8216ed0d50c3Schristos object,
8217ed0d50c3Schristos data_shndx,
8218ed0d50c3Schristos prelocs,
8219ed0d50c3Schristos reloc_count,
8220ed0d50c3Schristos output_section,
8221ed0d50c3Schristos needs_special_offset_handling,
8222ed0d50c3Schristos local_symbol_count,
8223ed0d50c3Schristos plocal_symbols,
8224ed0d50c3Schristos rr);
8225ed0d50c3Schristos }
8226ed0d50c3Schristos
8227ed0d50c3Schristos // Scan the relocs for --emit-relocs.
8228ed0d50c3Schristos
8229ed0d50c3Schristos template<int size, bool big_endian>
8230ed0d50c3Schristos void
emit_relocs_scan(Symbol_table * symtab,Layout * layout,Sized_relobj_file<size,big_endian> * object,unsigned int data_shndx,unsigned int sh_type,const unsigned char * prelocs,size_t reloc_count,Output_section * output_section,bool needs_special_offset_handling,size_t local_symbol_count,const unsigned char * plocal_syms,Relocatable_relocs * rr)8231ed0d50c3Schristos Target_aarch64<size, big_endian>::emit_relocs_scan(
8232ed0d50c3Schristos Symbol_table* symtab,
8233ed0d50c3Schristos Layout* layout,
8234ed0d50c3Schristos Sized_relobj_file<size, big_endian>* object,
8235ed0d50c3Schristos unsigned int data_shndx,
8236ed0d50c3Schristos unsigned int sh_type,
8237ed0d50c3Schristos const unsigned char* prelocs,
8238ed0d50c3Schristos size_t reloc_count,
8239ed0d50c3Schristos Output_section* output_section,
8240ed0d50c3Schristos bool needs_special_offset_handling,
8241ed0d50c3Schristos size_t local_symbol_count,
8242ed0d50c3Schristos const unsigned char* plocal_syms,
8243ed0d50c3Schristos Relocatable_relocs* rr)
8244ed0d50c3Schristos {
8245ed0d50c3Schristos typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
8246ed0d50c3Schristos Classify_reloc;
8247ed0d50c3Schristos typedef gold::Default_emit_relocs_strategy<Classify_reloc>
8248ed0d50c3Schristos Emit_relocs_strategy;
8249ed0d50c3Schristos
8250ed0d50c3Schristos gold_assert(sh_type == elfcpp::SHT_RELA);
8251ed0d50c3Schristos
8252ed0d50c3Schristos gold::scan_relocatable_relocs<size, big_endian, Emit_relocs_strategy>(
8253ed0d50c3Schristos symtab,
8254ed0d50c3Schristos layout,
8255ed0d50c3Schristos object,
8256ed0d50c3Schristos data_shndx,
8257ed0d50c3Schristos prelocs,
8258ed0d50c3Schristos reloc_count,
8259ed0d50c3Schristos output_section,
8260ed0d50c3Schristos needs_special_offset_handling,
8261ed0d50c3Schristos local_symbol_count,
8262ed0d50c3Schristos plocal_syms,
8263ed0d50c3Schristos rr);
8264ed0d50c3Schristos }
8265ed0d50c3Schristos
8266ed0d50c3Schristos // Relocate a section during a relocatable link.
8267ed0d50c3Schristos
8268ed0d50c3Schristos template<int size, bool big_endian>
8269ed0d50c3Schristos void
relocate_relocs(const Relocate_info<size,big_endian> * relinfo,unsigned int sh_type,const unsigned char * prelocs,size_t reloc_count,Output_section * output_section,typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,unsigned char * view,typename elfcpp::Elf_types<size>::Elf_Addr view_address,section_size_type view_size,unsigned char * reloc_view,section_size_type reloc_view_size)8270ed0d50c3Schristos Target_aarch64<size, big_endian>::relocate_relocs(
8271ed0d50c3Schristos const Relocate_info<size, big_endian>* relinfo,
8272ed0d50c3Schristos unsigned int sh_type,
8273ed0d50c3Schristos const unsigned char* prelocs,
8274ed0d50c3Schristos size_t reloc_count,
8275ed0d50c3Schristos Output_section* output_section,
8276ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
8277ed0d50c3Schristos unsigned char* view,
8278ed0d50c3Schristos typename elfcpp::Elf_types<size>::Elf_Addr view_address,
8279ed0d50c3Schristos section_size_type view_size,
8280ed0d50c3Schristos unsigned char* reloc_view,
8281ed0d50c3Schristos section_size_type reloc_view_size)
8282ed0d50c3Schristos {
8283ed0d50c3Schristos typedef gold::Default_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
8284ed0d50c3Schristos Classify_reloc;
8285ed0d50c3Schristos
8286ed0d50c3Schristos gold_assert(sh_type == elfcpp::SHT_RELA);
8287ed0d50c3Schristos
8288ed0d50c3Schristos gold::relocate_relocs<size, big_endian, Classify_reloc>(
8289ed0d50c3Schristos relinfo,
8290ed0d50c3Schristos prelocs,
8291ed0d50c3Schristos reloc_count,
8292ed0d50c3Schristos output_section,
8293ed0d50c3Schristos offset_in_output_section,
8294ed0d50c3Schristos view,
8295ed0d50c3Schristos view_address,
8296ed0d50c3Schristos view_size,
8297ed0d50c3Schristos reloc_view,
8298ed0d50c3Schristos reloc_view_size);
8299ed0d50c3Schristos }
8300ed0d50c3Schristos
8301ed0d50c3Schristos
8302ed0d50c3Schristos // Return whether this is a 3-insn erratum sequence.
8303ed0d50c3Schristos
8304ed0d50c3Schristos template<int size, bool big_endian>
8305ed0d50c3Schristos bool
is_erratum_843419_sequence(typename elfcpp::Swap<32,big_endian>::Valtype insn1,typename elfcpp::Swap<32,big_endian>::Valtype insn2,typename elfcpp::Swap<32,big_endian>::Valtype insn3)8306ed0d50c3Schristos Target_aarch64<size, big_endian>::is_erratum_843419_sequence(
8307ed0d50c3Schristos typename elfcpp::Swap<32,big_endian>::Valtype insn1,
8308ed0d50c3Schristos typename elfcpp::Swap<32,big_endian>::Valtype insn2,
8309ed0d50c3Schristos typename elfcpp::Swap<32,big_endian>::Valtype insn3)
8310ed0d50c3Schristos {
8311ed0d50c3Schristos unsigned rt1, rt2;
8312ed0d50c3Schristos bool load, pair;
8313ed0d50c3Schristos
8314ed0d50c3Schristos // The 2nd insn is a single register load or store; or register pair
8315ed0d50c3Schristos // store.
8316ed0d50c3Schristos if (Insn_utilities::aarch64_mem_op_p(insn2, &rt1, &rt2, &pair, &load)
8317ed0d50c3Schristos && (!pair || (pair && !load)))
8318ed0d50c3Schristos {
8319ed0d50c3Schristos // The 3rd insn is a load or store instruction from the "Load/store
8320ed0d50c3Schristos // register (unsigned immediate)" encoding class, using Rn as the
8321ed0d50c3Schristos // base address register.
8322ed0d50c3Schristos if (Insn_utilities::aarch64_ldst_uimm(insn3)
8323ed0d50c3Schristos && (Insn_utilities::aarch64_rn(insn3)
8324ed0d50c3Schristos == Insn_utilities::aarch64_rd(insn1)))
8325ed0d50c3Schristos return true;
8326ed0d50c3Schristos }
8327ed0d50c3Schristos return false;
8328ed0d50c3Schristos }
8329ed0d50c3Schristos
8330ed0d50c3Schristos
8331ed0d50c3Schristos // Return whether this is a 835769 sequence.
8332ed0d50c3Schristos // (Similarly implemented as in elfnn-aarch64.c.)
8333ed0d50c3Schristos
8334ed0d50c3Schristos template<int size, bool big_endian>
8335ed0d50c3Schristos bool
is_erratum_835769_sequence(typename elfcpp::Swap<32,big_endian>::Valtype insn1,typename elfcpp::Swap<32,big_endian>::Valtype insn2)8336ed0d50c3Schristos Target_aarch64<size, big_endian>::is_erratum_835769_sequence(
8337ed0d50c3Schristos typename elfcpp::Swap<32,big_endian>::Valtype insn1,
8338ed0d50c3Schristos typename elfcpp::Swap<32,big_endian>::Valtype insn2)
8339ed0d50c3Schristos {
8340ed0d50c3Schristos uint32_t rt;
834106324dcfSchristos uint32_t rt2 = 0;
8342ed0d50c3Schristos uint32_t rn;
8343ed0d50c3Schristos uint32_t rm;
8344ed0d50c3Schristos uint32_t ra;
8345ed0d50c3Schristos bool pair;
8346ed0d50c3Schristos bool load;
8347ed0d50c3Schristos
8348ed0d50c3Schristos if (Insn_utilities::aarch64_mlxl(insn2)
8349ed0d50c3Schristos && Insn_utilities::aarch64_mem_op_p (insn1, &rt, &rt2, &pair, &load))
8350ed0d50c3Schristos {
8351ed0d50c3Schristos /* Any SIMD memory op is independent of the subsequent MLA
8352ed0d50c3Schristos by definition of the erratum. */
8353ed0d50c3Schristos if (Insn_utilities::aarch64_bit(insn1, 26))
8354ed0d50c3Schristos return true;
8355ed0d50c3Schristos
8356ed0d50c3Schristos /* If not SIMD, check for integer memory ops and MLA relationship. */
8357ed0d50c3Schristos rn = Insn_utilities::aarch64_rn(insn2);
8358ed0d50c3Schristos ra = Insn_utilities::aarch64_ra(insn2);
8359ed0d50c3Schristos rm = Insn_utilities::aarch64_rm(insn2);
8360ed0d50c3Schristos
8361ed0d50c3Schristos /* If this is a load and there's a true(RAW) dependency, we are safe
8362ed0d50c3Schristos and this is not an erratum sequence. */
8363ed0d50c3Schristos if (load &&
8364ed0d50c3Schristos (rt == rn || rt == rm || rt == ra
8365ed0d50c3Schristos || (pair && (rt2 == rn || rt2 == rm || rt2 == ra))))
8366ed0d50c3Schristos return false;
8367ed0d50c3Schristos
8368ed0d50c3Schristos /* We conservatively put out stubs for all other cases (including
8369ed0d50c3Schristos writebacks). */
8370ed0d50c3Schristos return true;
8371ed0d50c3Schristos }
8372ed0d50c3Schristos
8373ed0d50c3Schristos return false;
8374ed0d50c3Schristos }
8375ed0d50c3Schristos
8376ed0d50c3Schristos
8377ed0d50c3Schristos // Helper method to create erratum stub for ST_E_843419 and ST_E_835769.
8378ed0d50c3Schristos
8379ed0d50c3Schristos template<int size, bool big_endian>
8380ed0d50c3Schristos void
create_erratum_stub(AArch64_relobj<size,big_endian> * relobj,unsigned int shndx,section_size_type erratum_insn_offset,Address erratum_address,typename Insn_utilities::Insntype erratum_insn,int erratum_type,unsigned int e843419_adrp_offset)8381ed0d50c3Schristos Target_aarch64<size, big_endian>::create_erratum_stub(
8382ed0d50c3Schristos AArch64_relobj<size, big_endian>* relobj,
8383ed0d50c3Schristos unsigned int shndx,
8384ed0d50c3Schristos section_size_type erratum_insn_offset,
8385ed0d50c3Schristos Address erratum_address,
8386ed0d50c3Schristos typename Insn_utilities::Insntype erratum_insn,
8387ed0d50c3Schristos int erratum_type,
8388ed0d50c3Schristos unsigned int e843419_adrp_offset)
8389ed0d50c3Schristos {
8390ed0d50c3Schristos gold_assert(erratum_type == ST_E_843419 || erratum_type == ST_E_835769);
8391ed0d50c3Schristos The_stub_table* stub_table = relobj->stub_table(shndx);
8392ed0d50c3Schristos gold_assert(stub_table != NULL);
8393ed0d50c3Schristos if (stub_table->find_erratum_stub(relobj,
8394ed0d50c3Schristos shndx,
8395ed0d50c3Schristos erratum_insn_offset) == NULL)
8396ed0d50c3Schristos {
8397ed0d50c3Schristos const int BPI = AArch64_insn_utilities<big_endian>::BYTES_PER_INSN;
8398ed0d50c3Schristos The_erratum_stub* stub;
8399ed0d50c3Schristos if (erratum_type == ST_E_835769)
8400ed0d50c3Schristos stub = new The_erratum_stub(relobj, erratum_type, shndx,
8401ed0d50c3Schristos erratum_insn_offset);
8402ed0d50c3Schristos else if (erratum_type == ST_E_843419)
8403ed0d50c3Schristos stub = new E843419_stub<size, big_endian>(
8404ed0d50c3Schristos relobj, shndx, erratum_insn_offset, e843419_adrp_offset);
8405ed0d50c3Schristos else
8406ed0d50c3Schristos gold_unreachable();
8407ed0d50c3Schristos stub->set_erratum_insn(erratum_insn);
8408ed0d50c3Schristos stub->set_erratum_address(erratum_address);
8409ed0d50c3Schristos // For erratum ST_E_843419 and ST_E_835769, the destination address is
8410ed0d50c3Schristos // always the next insn after erratum insn.
8411ed0d50c3Schristos stub->set_destination_address(erratum_address + BPI);
8412ed0d50c3Schristos stub_table->add_erratum_stub(stub);
8413ed0d50c3Schristos }
8414ed0d50c3Schristos }
8415ed0d50c3Schristos
8416ed0d50c3Schristos
8417ed0d50c3Schristos // Scan erratum for section SHNDX range [output_address + span_start,
8418ed0d50c3Schristos // output_address + span_end). Note here we do not share the code with
8419ed0d50c3Schristos // scan_erratum_843419_span function, because for 843419 we optimize by only
8420ed0d50c3Schristos // scanning the last few insns of a page, whereas for 835769, we need to scan
8421ed0d50c3Schristos // every insn.
8422ed0d50c3Schristos
8423ed0d50c3Schristos template<int size, bool big_endian>
8424ed0d50c3Schristos void
scan_erratum_835769_span(AArch64_relobj<size,big_endian> * relobj,unsigned int shndx,const section_size_type span_start,const section_size_type span_end,unsigned char * input_view,Address output_address)8425ed0d50c3Schristos Target_aarch64<size, big_endian>::scan_erratum_835769_span(
8426ed0d50c3Schristos AArch64_relobj<size, big_endian>* relobj,
8427ed0d50c3Schristos unsigned int shndx,
8428ed0d50c3Schristos const section_size_type span_start,
8429ed0d50c3Schristos const section_size_type span_end,
8430ed0d50c3Schristos unsigned char* input_view,
8431ed0d50c3Schristos Address output_address)
8432ed0d50c3Schristos {
8433ed0d50c3Schristos typedef typename Insn_utilities::Insntype Insntype;
8434ed0d50c3Schristos
8435ed0d50c3Schristos const int BPI = AArch64_insn_utilities<big_endian>::BYTES_PER_INSN;
8436ed0d50c3Schristos
8437ed0d50c3Schristos // Adjust output_address and view to the start of span.
8438ed0d50c3Schristos output_address += span_start;
8439ed0d50c3Schristos input_view += span_start;
8440ed0d50c3Schristos
8441ed0d50c3Schristos section_size_type span_length = span_end - span_start;
8442ed0d50c3Schristos section_size_type offset = 0;
8443ed0d50c3Schristos for (offset = 0; offset + BPI < span_length; offset += BPI)
8444ed0d50c3Schristos {
8445ed0d50c3Schristos Insntype* ip = reinterpret_cast<Insntype*>(input_view + offset);
8446ed0d50c3Schristos Insntype insn1 = ip[0];
8447ed0d50c3Schristos Insntype insn2 = ip[1];
8448ed0d50c3Schristos if (is_erratum_835769_sequence(insn1, insn2))
8449ed0d50c3Schristos {
8450ed0d50c3Schristos Insntype erratum_insn = insn2;
8451ed0d50c3Schristos // "span_start + offset" is the offset for insn1. So for insn2, it is
8452ed0d50c3Schristos // "span_start + offset + BPI".
8453ed0d50c3Schristos section_size_type erratum_insn_offset = span_start + offset + BPI;
8454ed0d50c3Schristos Address erratum_address = output_address + offset + BPI;
8455ed0d50c3Schristos gold_info(_("Erratum 835769 found and fixed at \"%s\", "
8456ed0d50c3Schristos "section %d, offset 0x%08x."),
8457ed0d50c3Schristos relobj->name().c_str(), shndx,
8458ed0d50c3Schristos (unsigned int)(span_start + offset));
8459ed0d50c3Schristos
8460ed0d50c3Schristos this->create_erratum_stub(relobj, shndx,
8461ed0d50c3Schristos erratum_insn_offset, erratum_address,
8462ed0d50c3Schristos erratum_insn, ST_E_835769);
8463ed0d50c3Schristos offset += BPI; // Skip mac insn.
8464ed0d50c3Schristos }
8465ed0d50c3Schristos }
8466ed0d50c3Schristos } // End of "Target_aarch64::scan_erratum_835769_span".
8467ed0d50c3Schristos
8468ed0d50c3Schristos
8469ed0d50c3Schristos // Scan erratum for section SHNDX range
8470ed0d50c3Schristos // [output_address + span_start, output_address + span_end).
8471ed0d50c3Schristos
8472ed0d50c3Schristos template<int size, bool big_endian>
8473ed0d50c3Schristos void
scan_erratum_843419_span(AArch64_relobj<size,big_endian> * relobj,unsigned int shndx,const section_size_type span_start,const section_size_type span_end,unsigned char * input_view,Address output_address)8474ed0d50c3Schristos Target_aarch64<size, big_endian>::scan_erratum_843419_span(
8475ed0d50c3Schristos AArch64_relobj<size, big_endian>* relobj,
8476ed0d50c3Schristos unsigned int shndx,
8477ed0d50c3Schristos const section_size_type span_start,
8478ed0d50c3Schristos const section_size_type span_end,
8479ed0d50c3Schristos unsigned char* input_view,
8480ed0d50c3Schristos Address output_address)
8481ed0d50c3Schristos {
8482ed0d50c3Schristos typedef typename Insn_utilities::Insntype Insntype;
8483ed0d50c3Schristos
8484ed0d50c3Schristos // Adjust output_address and view to the start of span.
8485ed0d50c3Schristos output_address += span_start;
8486ed0d50c3Schristos input_view += span_start;
8487ed0d50c3Schristos
8488ed0d50c3Schristos if ((output_address & 0x03) != 0)
8489ed0d50c3Schristos return;
8490ed0d50c3Schristos
8491ed0d50c3Schristos section_size_type offset = 0;
8492ed0d50c3Schristos section_size_type span_length = span_end - span_start;
8493ed0d50c3Schristos // The first instruction must be ending at 0xFF8 or 0xFFC.
8494ed0d50c3Schristos unsigned int page_offset = output_address & 0xFFF;
8495ed0d50c3Schristos // Make sure starting position, that is "output_address+offset",
8496ed0d50c3Schristos // starts at page position 0xff8 or 0xffc.
8497ed0d50c3Schristos if (page_offset < 0xff8)
8498ed0d50c3Schristos offset = 0xff8 - page_offset;
8499ed0d50c3Schristos while (offset + 3 * Insn_utilities::BYTES_PER_INSN <= span_length)
8500ed0d50c3Schristos {
8501ed0d50c3Schristos Insntype* ip = reinterpret_cast<Insntype*>(input_view + offset);
8502ed0d50c3Schristos Insntype insn1 = ip[0];
8503ed0d50c3Schristos if (Insn_utilities::is_adrp(insn1))
8504ed0d50c3Schristos {
8505ed0d50c3Schristos Insntype insn2 = ip[1];
8506ed0d50c3Schristos Insntype insn3 = ip[2];
8507ed0d50c3Schristos Insntype erratum_insn;
8508ed0d50c3Schristos unsigned insn_offset;
8509ed0d50c3Schristos bool do_report = false;
8510ed0d50c3Schristos if (is_erratum_843419_sequence(insn1, insn2, insn3))
8511ed0d50c3Schristos {
8512ed0d50c3Schristos do_report = true;
8513ed0d50c3Schristos erratum_insn = insn3;
8514ed0d50c3Schristos insn_offset = 2 * Insn_utilities::BYTES_PER_INSN;
8515ed0d50c3Schristos }
8516ed0d50c3Schristos else if (offset + 4 * Insn_utilities::BYTES_PER_INSN <= span_length)
8517ed0d50c3Schristos {
8518ed0d50c3Schristos // Optionally we can have an insn between ins2 and ins3
8519ed0d50c3Schristos Insntype insn_opt = ip[2];
8520ed0d50c3Schristos // And insn_opt must not be a branch.
8521ed0d50c3Schristos if (!Insn_utilities::aarch64_b(insn_opt)
8522ed0d50c3Schristos && !Insn_utilities::aarch64_bl(insn_opt)
8523ed0d50c3Schristos && !Insn_utilities::aarch64_blr(insn_opt)
8524ed0d50c3Schristos && !Insn_utilities::aarch64_br(insn_opt))
8525ed0d50c3Schristos {
8526ed0d50c3Schristos // And insn_opt must not write to dest reg in insn1. However
8527ed0d50c3Schristos // we do a conservative scan, which means we may fix/report
8528ed0d50c3Schristos // more than necessary, but it doesn't hurt.
8529ed0d50c3Schristos
8530ed0d50c3Schristos Insntype insn4 = ip[3];
8531ed0d50c3Schristos if (is_erratum_843419_sequence(insn1, insn2, insn4))
8532ed0d50c3Schristos {
8533ed0d50c3Schristos do_report = true;
8534ed0d50c3Schristos erratum_insn = insn4;
8535ed0d50c3Schristos insn_offset = 3 * Insn_utilities::BYTES_PER_INSN;
8536ed0d50c3Schristos }
8537ed0d50c3Schristos }
8538ed0d50c3Schristos }
8539ed0d50c3Schristos if (do_report)
8540ed0d50c3Schristos {
8541ed0d50c3Schristos unsigned int erratum_insn_offset =
8542ed0d50c3Schristos span_start + offset + insn_offset;
8543ed0d50c3Schristos Address erratum_address =
8544ed0d50c3Schristos output_address + offset + insn_offset;
8545ed0d50c3Schristos create_erratum_stub(relobj, shndx,
8546ed0d50c3Schristos erratum_insn_offset, erratum_address,
8547ed0d50c3Schristos erratum_insn, ST_E_843419,
8548ed0d50c3Schristos span_start + offset);
8549ed0d50c3Schristos }
8550ed0d50c3Schristos }
8551ed0d50c3Schristos
8552ed0d50c3Schristos // Advance to next candidate instruction. We only consider instruction
8553ed0d50c3Schristos // sequences starting at a page offset of 0xff8 or 0xffc.
8554ed0d50c3Schristos page_offset = (output_address + offset) & 0xfff;
8555ed0d50c3Schristos if (page_offset == 0xff8)
8556ed0d50c3Schristos offset += 4;
8557ed0d50c3Schristos else // (page_offset == 0xffc), we move to next page's 0xff8.
8558ed0d50c3Schristos offset += 0xffc;
8559ed0d50c3Schristos }
8560ed0d50c3Schristos } // End of "Target_aarch64::scan_erratum_843419_span".
8561ed0d50c3Schristos
8562ed0d50c3Schristos
8563ed0d50c3Schristos // The selector for aarch64 object files.
8564ed0d50c3Schristos
8565ed0d50c3Schristos template<int size, bool big_endian>
8566ed0d50c3Schristos class Target_selector_aarch64 : public Target_selector
8567ed0d50c3Schristos {
8568ed0d50c3Schristos public:
8569ed0d50c3Schristos Target_selector_aarch64();
8570ed0d50c3Schristos
8571ed0d50c3Schristos virtual Target*
do_instantiate_target()8572ed0d50c3Schristos do_instantiate_target()
8573ed0d50c3Schristos { return new Target_aarch64<size, big_endian>(); }
8574ed0d50c3Schristos };
8575ed0d50c3Schristos
8576ed0d50c3Schristos template<>
Target_selector_aarch64()8577ed0d50c3Schristos Target_selector_aarch64<32, true>::Target_selector_aarch64()
8578ed0d50c3Schristos : Target_selector(elfcpp::EM_AARCH64, 32, true,
8579ed0d50c3Schristos "elf32-bigaarch64", "aarch64_elf32_be_vec")
8580ed0d50c3Schristos { }
8581ed0d50c3Schristos
8582ed0d50c3Schristos template<>
Target_selector_aarch64()8583ed0d50c3Schristos Target_selector_aarch64<32, false>::Target_selector_aarch64()
8584ed0d50c3Schristos : Target_selector(elfcpp::EM_AARCH64, 32, false,
8585ed0d50c3Schristos "elf32-littleaarch64", "aarch64_elf32_le_vec")
8586ed0d50c3Schristos { }
8587ed0d50c3Schristos
8588ed0d50c3Schristos template<>
Target_selector_aarch64()8589ed0d50c3Schristos Target_selector_aarch64<64, true>::Target_selector_aarch64()
8590ed0d50c3Schristos : Target_selector(elfcpp::EM_AARCH64, 64, true,
8591ed0d50c3Schristos "elf64-bigaarch64", "aarch64_elf64_be_vec")
8592ed0d50c3Schristos { }
8593ed0d50c3Schristos
8594ed0d50c3Schristos template<>
Target_selector_aarch64()8595ed0d50c3Schristos Target_selector_aarch64<64, false>::Target_selector_aarch64()
8596ed0d50c3Schristos : Target_selector(elfcpp::EM_AARCH64, 64, false,
8597ed0d50c3Schristos "elf64-littleaarch64", "aarch64_elf64_le_vec")
8598ed0d50c3Schristos { }
8599ed0d50c3Schristos
8600ed0d50c3Schristos Target_selector_aarch64<32, true> target_selector_aarch64elf32b;
8601ed0d50c3Schristos Target_selector_aarch64<32, false> target_selector_aarch64elf32;
8602ed0d50c3Schristos Target_selector_aarch64<64, true> target_selector_aarch64elfb;
8603ed0d50c3Schristos Target_selector_aarch64<64, false> target_selector_aarch64elf;
8604ed0d50c3Schristos
8605ed0d50c3Schristos } // End anonymous namespace.
8606