/src/binutils-gdb/bfd/elfxx-aarch64.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* AArch64-specific support for ELF. |
2 | | Copyright (C) 2009-2025 Free Software Foundation, Inc. |
3 | | Contributed by ARM Ltd. |
4 | | |
5 | | This file is part of BFD, the Binary File Descriptor library. |
6 | | |
7 | | This program is free software; you can redistribute it and/or modify |
8 | | it under the terms of the GNU General Public License as published by |
9 | | the Free Software Foundation; either version 3 of the License, or |
10 | | (at your option) any later version. |
11 | | |
12 | | This program is distributed in the hope that it will be useful, |
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | GNU General Public License for more details. |
16 | | |
17 | | You should have received a copy of the GNU General Public License |
18 | | along with this program; see the file COPYING3. If not, |
19 | | see <http://www.gnu.org/licenses/>. */ |
20 | | |
21 | | #include "sysdep.h" |
22 | | #include "bfd.h" |
23 | | #include "elf-bfd.h" |
24 | | #include "elfxx-aarch64.h" |
25 | | #include "libbfd.h" |
26 | | #include <stdarg.h> |
27 | | #include <string.h> |
28 | | |
29 | 0 | #define MASK(n) ((1u << (n)) - 1) |
30 | | |
31 | | /* Sign-extend VALUE, which has the indicated number of BITS. */ |
32 | | |
33 | | bfd_signed_vma |
34 | | _bfd_aarch64_sign_extend (bfd_vma value, int bits) |
35 | 0 | { |
36 | 0 | if (value & ((bfd_vma) 1 << (bits - 1))) |
37 | | /* VALUE is negative. */ |
38 | 0 | value |= ((bfd_vma) - 1) << bits; |
39 | |
|
40 | 0 | return value; |
41 | 0 | } |
42 | | |
43 | | /* Decode the IMM field of ADRP. */ |
44 | | |
45 | | uint32_t |
46 | | _bfd_aarch64_decode_adrp_imm (uint32_t insn) |
47 | 0 | { |
48 | 0 | return (((insn >> 5) & MASK (19)) << 2) | ((insn >> 29) & MASK (2)); |
49 | 0 | } |
50 | | |
51 | | /* Reencode the imm field of add immediate. */ |
52 | | static inline uint32_t |
53 | | reencode_add_imm (uint32_t insn, uint32_t imm) |
54 | 0 | { |
55 | 0 | return (insn & ~(MASK (12) << 10)) | ((imm & MASK (12)) << 10); |
56 | 0 | } |
57 | | |
58 | | /* Reencode the IMM field of ADR. */ |
59 | | |
60 | | uint32_t |
61 | | _bfd_aarch64_reencode_adr_imm (uint32_t insn, uint32_t imm) |
62 | 0 | { |
63 | 0 | return (insn & ~((MASK (2) << 29) | (MASK (19) << 5))) |
64 | 0 | | ((imm & MASK (2)) << 29) | ((imm & (MASK (19) << 2)) << 3); |
65 | 0 | } |
66 | | |
67 | | /* Reencode the imm field of ld/st pos immediate. */ |
68 | | static inline uint32_t |
69 | | reencode_ldst_pos_imm (uint32_t insn, uint32_t imm) |
70 | 0 | { |
71 | 0 | return (insn & ~(MASK (12) << 10)) | ((imm & MASK (12)) << 10); |
72 | 0 | } |
73 | | |
74 | | /* Encode the 26-bit offset of unconditional branch. */ |
75 | | static inline uint32_t |
76 | | reencode_branch_ofs_26 (uint32_t insn, uint32_t ofs) |
77 | 0 | { |
78 | 0 | return (insn & ~MASK (26)) | (ofs & MASK (26)); |
79 | 0 | } |
80 | | |
81 | | /* Encode the 19-bit offset of conditional branch and compare & branch. */ |
82 | | static inline uint32_t |
83 | | reencode_cond_branch_ofs_19 (uint32_t insn, uint32_t ofs) |
84 | 0 | { |
85 | 0 | return (insn & ~(MASK (19) << 5)) | ((ofs & MASK (19)) << 5); |
86 | 0 | } |
87 | | |
88 | | /* Decode the 19-bit offset of load literal. */ |
89 | | static inline uint32_t |
90 | | reencode_ld_lit_ofs_19 (uint32_t insn, uint32_t ofs) |
91 | 0 | { |
92 | 0 | return (insn & ~(MASK (19) << 5)) | ((ofs & MASK (19)) << 5); |
93 | 0 | } |
94 | | |
95 | | /* Encode the 14-bit offset of test & branch. */ |
96 | | static inline uint32_t |
97 | | reencode_tst_branch_ofs_14 (uint32_t insn, uint32_t ofs) |
98 | 0 | { |
99 | 0 | return (insn & ~(MASK (14) << 5)) | ((ofs & MASK (14)) << 5); |
100 | 0 | } |
101 | | |
102 | | /* Reencode the imm field of move wide. */ |
103 | | static inline uint32_t |
104 | | reencode_movw_imm (uint32_t insn, uint32_t imm) |
105 | 0 | { |
106 | 0 | return (insn & ~(MASK (16) << 5)) | ((imm & MASK (16)) << 5); |
107 | 0 | } |
108 | | |
109 | | /* Reencode mov[zn] to movz. */ |
110 | | static inline uint32_t |
111 | | reencode_movzn_to_movz (uint32_t opcode) |
112 | 0 | { |
113 | 0 | return opcode | (1 << 30); |
114 | 0 | } |
115 | | |
116 | | /* Reencode mov[zn] to movn. */ |
117 | | static inline uint32_t |
118 | | reencode_movzn_to_movn (uint32_t opcode) |
119 | 0 | { |
120 | 0 | return opcode & ~(1 << 30); |
121 | 0 | } |
122 | | |
123 | | /* Return non-zero if the indicated VALUE has overflowed the maximum |
124 | | range expressible by a unsigned number with the indicated number of |
125 | | BITS. */ |
126 | | |
127 | | static bfd_reloc_status_type |
128 | | aarch64_unsigned_overflow (bfd_vma value, unsigned int bits) |
129 | 0 | { |
130 | 0 | bfd_vma lim; |
131 | 0 | if (bits >= sizeof (bfd_vma) * 8) |
132 | 0 | return bfd_reloc_ok; |
133 | 0 | lim = (bfd_vma) 1 << bits; |
134 | 0 | if (value >= lim) |
135 | 0 | return bfd_reloc_overflow; |
136 | 0 | return bfd_reloc_ok; |
137 | 0 | } |
138 | | |
139 | | /* Return non-zero if the indicated VALUE has overflowed the maximum |
140 | | range expressible by an signed number with the indicated number of |
141 | | BITS. */ |
142 | | |
143 | | static bfd_reloc_status_type |
144 | | aarch64_signed_overflow (bfd_vma value, unsigned int bits) |
145 | 0 | { |
146 | 0 | bfd_signed_vma svalue = (bfd_signed_vma) value; |
147 | 0 | bfd_signed_vma lim; |
148 | |
|
149 | 0 | if (bits >= sizeof (bfd_vma) * 8) |
150 | 0 | return bfd_reloc_ok; |
151 | 0 | lim = (bfd_signed_vma) 1 << (bits - 1); |
152 | 0 | if (svalue < -lim || svalue >= lim) |
153 | 0 | return bfd_reloc_overflow; |
154 | 0 | return bfd_reloc_ok; |
155 | 0 | } |
156 | | |
157 | | /* Insert the addend/value into the instruction or data object being |
158 | | relocated. */ |
159 | | bfd_reloc_status_type |
160 | | _bfd_aarch64_elf_put_addend (bfd *abfd, |
161 | | bfd_byte *address, bfd_reloc_code_real_type r_type, |
162 | | reloc_howto_type *howto, bfd_signed_vma addend) |
163 | 0 | { |
164 | 0 | bfd_reloc_status_type status = bfd_reloc_ok; |
165 | 0 | bfd_signed_vma old_addend = addend; |
166 | 0 | bfd_vma contents; |
167 | 0 | int size; |
168 | |
|
169 | 0 | size = bfd_get_reloc_size (howto); |
170 | 0 | switch (size) |
171 | 0 | { |
172 | 0 | case 0: |
173 | 0 | return status; |
174 | 0 | case 2: |
175 | 0 | contents = bfd_get_16 (abfd, address); |
176 | 0 | break; |
177 | 0 | case 4: |
178 | 0 | if (howto->src_mask != 0xffffffff) |
179 | | /* Must be 32-bit instruction, always little-endian. */ |
180 | 0 | contents = bfd_getl32 (address); |
181 | 0 | else |
182 | | /* Must be 32-bit data (endianness dependent). */ |
183 | 0 | contents = bfd_get_32 (abfd, address); |
184 | 0 | break; |
185 | 0 | case 8: |
186 | 0 | contents = bfd_get_64 (abfd, address); |
187 | 0 | break; |
188 | 0 | default: |
189 | 0 | abort (); |
190 | 0 | } |
191 | | |
192 | 0 | switch (howto->complain_on_overflow) |
193 | 0 | { |
194 | 0 | case complain_overflow_dont: |
195 | 0 | break; |
196 | 0 | case complain_overflow_signed: |
197 | 0 | status = aarch64_signed_overflow (addend, |
198 | 0 | howto->bitsize + howto->rightshift); |
199 | 0 | break; |
200 | 0 | case complain_overflow_unsigned: |
201 | 0 | status = aarch64_unsigned_overflow (addend, |
202 | 0 | howto->bitsize + howto->rightshift); |
203 | 0 | break; |
204 | 0 | case complain_overflow_bitfield: |
205 | 0 | default: |
206 | 0 | abort (); |
207 | 0 | } |
208 | | |
209 | 0 | addend >>= howto->rightshift; |
210 | |
|
211 | 0 | switch (r_type) |
212 | 0 | { |
213 | 0 | case BFD_RELOC_AARCH64_CALL26: |
214 | 0 | case BFD_RELOC_AARCH64_JUMP26: |
215 | 0 | contents = reencode_branch_ofs_26 (contents, addend); |
216 | 0 | break; |
217 | | |
218 | 0 | case BFD_RELOC_AARCH64_BRANCH19: |
219 | 0 | contents = reencode_cond_branch_ofs_19 (contents, addend); |
220 | 0 | break; |
221 | | |
222 | 0 | case BFD_RELOC_AARCH64_TSTBR14: |
223 | 0 | contents = reencode_tst_branch_ofs_14 (contents, addend); |
224 | 0 | break; |
225 | | |
226 | 0 | case BFD_RELOC_AARCH64_GOT_LD_PREL19: |
227 | 0 | case BFD_RELOC_AARCH64_LD_LO19_PCREL: |
228 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19: |
229 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19: |
230 | 0 | if (old_addend & ((1 << howto->rightshift) - 1)) |
231 | 0 | return bfd_reloc_overflow; |
232 | 0 | contents = reencode_ld_lit_ofs_19 (contents, addend); |
233 | 0 | break; |
234 | | |
235 | 0 | case BFD_RELOC_AARCH64_TLSDESC_CALL: |
236 | 0 | break; |
237 | | |
238 | 0 | case BFD_RELOC_AARCH64_ADR_GOT_PAGE: |
239 | 0 | case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL: |
240 | 0 | case BFD_RELOC_AARCH64_ADR_HI21_PCREL: |
241 | 0 | case BFD_RELOC_AARCH64_ADR_LO21_PCREL: |
242 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21: |
243 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21: |
244 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21: |
245 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21: |
246 | 0 | case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: |
247 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21: |
248 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21: |
249 | 0 | contents = _bfd_aarch64_reencode_adr_imm (contents, addend); |
250 | 0 | break; |
251 | | |
252 | 0 | case BFD_RELOC_AARCH64_ADD_LO12: |
253 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12: |
254 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC: |
255 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_HI12: |
256 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12: |
257 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: |
258 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC: |
259 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12: |
260 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12: |
261 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC: |
262 | | /* Corresponds to: add rd, rn, #uimm12 to provide the low order |
263 | | 12 bits of the page offset following |
264 | | BFD_RELOC_AARCH64_ADR_HI21_PCREL which computes the |
265 | | (pc-relative) page base. */ |
266 | 0 | contents = reencode_add_imm (contents, addend); |
267 | 0 | break; |
268 | | |
269 | 0 | case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14: |
270 | 0 | case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC: |
271 | 0 | case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15: |
272 | 0 | case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15: |
273 | 0 | case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC: |
274 | 0 | case BFD_RELOC_AARCH64_LDST128_LO12: |
275 | 0 | case BFD_RELOC_AARCH64_LDST16_LO12: |
276 | 0 | case BFD_RELOC_AARCH64_LDST32_LO12: |
277 | 0 | case BFD_RELOC_AARCH64_LDST64_LO12: |
278 | 0 | case BFD_RELOC_AARCH64_LDST8_LO12: |
279 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC: |
280 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12: |
281 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC: |
282 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: |
283 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12: |
284 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC: |
285 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12: |
286 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC: |
287 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12: |
288 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC: |
289 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12: |
290 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC: |
291 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12: |
292 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: |
293 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12: |
294 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: |
295 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12: |
296 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: |
297 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12: |
298 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: |
299 | 0 | if (old_addend & ((1 << howto->rightshift) - 1)) |
300 | 0 | return bfd_reloc_overflow; |
301 | | /* Used for ldr*|str* rt, [rn, #uimm12] to provide the low order |
302 | | 12 bits address offset. */ |
303 | 0 | contents = reencode_ldst_pos_imm (contents, addend); |
304 | 0 | break; |
305 | | |
306 | | /* Group relocations to create high bits of a 16, 32, 48 or 64 |
307 | | bit signed data or abs address inline. Will change |
308 | | instruction to MOVN or MOVZ depending on sign of calculated |
309 | | value. */ |
310 | | |
311 | 0 | case BFD_RELOC_AARCH64_MOVW_G0_S: |
312 | 0 | case BFD_RELOC_AARCH64_MOVW_G1_S: |
313 | 0 | case BFD_RELOC_AARCH64_MOVW_G2_S: |
314 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G0: |
315 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G1: |
316 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G2: |
317 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G3: |
318 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0: |
319 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1: |
320 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2: |
321 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0: |
322 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1: |
323 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2: |
324 | | /* NOTE: We can only come here with movz or movn. */ |
325 | 0 | if (addend < 0) |
326 | 0 | { |
327 | | /* Force use of MOVN. */ |
328 | 0 | addend = ~addend; |
329 | 0 | contents = reencode_movzn_to_movn (contents); |
330 | 0 | } |
331 | 0 | else |
332 | 0 | { |
333 | | /* Force use of MOVZ. */ |
334 | 0 | contents = reencode_movzn_to_movz (contents); |
335 | 0 | } |
336 | | /* Fall through. */ |
337 | | |
338 | | /* Group relocations to create a 16, 32, 48 or 64 bit unsigned |
339 | | data or abs address inline. */ |
340 | |
|
341 | 0 | case BFD_RELOC_AARCH64_MOVW_G0: |
342 | 0 | case BFD_RELOC_AARCH64_MOVW_G0_NC: |
343 | 0 | case BFD_RELOC_AARCH64_MOVW_G1: |
344 | 0 | case BFD_RELOC_AARCH64_MOVW_G1_NC: |
345 | 0 | case BFD_RELOC_AARCH64_MOVW_G2: |
346 | 0 | case BFD_RELOC_AARCH64_MOVW_G2_NC: |
347 | 0 | case BFD_RELOC_AARCH64_MOVW_G3: |
348 | 0 | case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC: |
349 | 0 | case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1: |
350 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G0_NC: |
351 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G1_NC: |
352 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G2_NC: |
353 | 0 | case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC: |
354 | 0 | case BFD_RELOC_AARCH64_TLSDESC_OFF_G1: |
355 | 0 | case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC: |
356 | 0 | case BFD_RELOC_AARCH64_TLSGD_MOVW_G1: |
357 | 0 | case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC: |
358 | 0 | case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1: |
359 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: |
360 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC: |
361 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC: |
362 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC: |
363 | 0 | contents = reencode_movw_imm (contents, addend); |
364 | 0 | break; |
365 | | |
366 | 0 | default: |
367 | | /* Repack simple data */ |
368 | 0 | if (howto->dst_mask & (howto->dst_mask + 1)) |
369 | 0 | return bfd_reloc_notsupported; |
370 | | |
371 | 0 | contents = ((contents & ~howto->dst_mask) | (addend & howto->dst_mask)); |
372 | 0 | break; |
373 | 0 | } |
374 | | |
375 | 0 | switch (size) |
376 | 0 | { |
377 | 0 | case 2: |
378 | 0 | bfd_put_16 (abfd, contents, address); |
379 | 0 | break; |
380 | 0 | case 4: |
381 | 0 | if (howto->dst_mask != 0xffffffff) |
382 | | /* must be 32-bit instruction, always little-endian */ |
383 | 0 | bfd_putl32 (contents, address); |
384 | 0 | else |
385 | | /* must be 32-bit data (endianness dependent) */ |
386 | 0 | bfd_put_32 (abfd, contents, address); |
387 | 0 | break; |
388 | 0 | case 8: |
389 | 0 | bfd_put_64 (abfd, contents, address); |
390 | 0 | break; |
391 | 0 | default: |
392 | 0 | abort (); |
393 | 0 | } |
394 | | |
395 | 0 | return status; |
396 | 0 | } |
397 | | |
398 | | bfd_vma |
399 | | _bfd_aarch64_elf_resolve_relocation (bfd *input_bfd, |
400 | | bfd_reloc_code_real_type r_type, |
401 | | bfd_vma place, bfd_vma value, |
402 | | bfd_vma addend, bool weak_undef_p) |
403 | 0 | { |
404 | 0 | bool tls_reloc = true; |
405 | 0 | switch (r_type) |
406 | 0 | { |
407 | 0 | case BFD_RELOC_AARCH64_NONE: |
408 | 0 | case BFD_RELOC_AARCH64_TLSDESC_CALL: |
409 | 0 | break; |
410 | | |
411 | 0 | case BFD_RELOC_AARCH64_16_PCREL: |
412 | 0 | case BFD_RELOC_AARCH64_32_PCREL: |
413 | 0 | case BFD_RELOC_AARCH64_64_PCREL: |
414 | 0 | case BFD_RELOC_AARCH64_ADR_LO21_PCREL: |
415 | 0 | case BFD_RELOC_AARCH64_BRANCH19: |
416 | 0 | case BFD_RELOC_AARCH64_LD_LO19_PCREL: |
417 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G0: |
418 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G0_NC: |
419 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G1: |
420 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G1_NC: |
421 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G2: |
422 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G2_NC: |
423 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G3: |
424 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21: |
425 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19: |
426 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21: |
427 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19: |
428 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21: |
429 | 0 | case BFD_RELOC_AARCH64_TSTBR14: |
430 | 0 | if (weak_undef_p) |
431 | 0 | value = place; |
432 | 0 | value = value + addend - place; |
433 | 0 | break; |
434 | | |
435 | 0 | case BFD_RELOC_AARCH64_CALL26: |
436 | 0 | case BFD_RELOC_AARCH64_JUMP26: |
437 | 0 | value = value + addend - place; |
438 | 0 | break; |
439 | | |
440 | 0 | case BFD_RELOC_AARCH64_16: |
441 | 0 | case BFD_RELOC_AARCH64_32: |
442 | 0 | case BFD_RELOC_AARCH64_MOVW_G0: |
443 | 0 | case BFD_RELOC_AARCH64_MOVW_G0_NC: |
444 | 0 | case BFD_RELOC_AARCH64_MOVW_G0_S: |
445 | 0 | case BFD_RELOC_AARCH64_MOVW_G1: |
446 | 0 | case BFD_RELOC_AARCH64_MOVW_G1_NC: |
447 | 0 | case BFD_RELOC_AARCH64_MOVW_G1_S: |
448 | 0 | case BFD_RELOC_AARCH64_MOVW_G2: |
449 | 0 | case BFD_RELOC_AARCH64_MOVW_G2_NC: |
450 | 0 | case BFD_RELOC_AARCH64_MOVW_G2_S: |
451 | 0 | case BFD_RELOC_AARCH64_MOVW_G3: |
452 | 0 | tls_reloc = false; |
453 | | /* fall-through. */ |
454 | 0 | case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC: |
455 | 0 | case BFD_RELOC_AARCH64_TLSDESC_OFF_G1: |
456 | 0 | case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC: |
457 | 0 | case BFD_RELOC_AARCH64_TLSGD_MOVW_G1: |
458 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_HI12: |
459 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12: |
460 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: |
461 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12: |
462 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12: |
463 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12: |
464 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12: |
465 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0: |
466 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: |
467 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1: |
468 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC: |
469 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2: |
470 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12: |
471 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12: |
472 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12: |
473 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12: |
474 | | /* Weak Symbols and TLS relocations are implementation defined. For this |
475 | | case we choose to emit 0. */ |
476 | 0 | if (weak_undef_p && tls_reloc) |
477 | 0 | { |
478 | 0 | _bfd_error_handler (_("%pB: warning: Weak TLS is implementation " |
479 | 0 | "defined and may not work as expected"), |
480 | 0 | input_bfd); |
481 | 0 | value = place; |
482 | 0 | } |
483 | 0 | value = value + addend; |
484 | 0 | break; |
485 | | |
486 | 0 | case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL: |
487 | 0 | case BFD_RELOC_AARCH64_ADR_HI21_PCREL: |
488 | 0 | if (weak_undef_p) |
489 | 0 | value = PG (place); |
490 | 0 | value = PG (value + addend) - PG (place); |
491 | 0 | break; |
492 | | |
493 | 0 | case BFD_RELOC_AARCH64_GOT_LD_PREL19: |
494 | 0 | value = value + addend - place; |
495 | 0 | break; |
496 | | |
497 | 0 | case BFD_RELOC_AARCH64_ADR_GOT_PAGE: |
498 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21: |
499 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21: |
500 | 0 | case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: |
501 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21: |
502 | 0 | value = PG (value + addend) - PG (place); |
503 | 0 | break; |
504 | | |
505 | | /* Caller must make sure addend is the base address of .got section. */ |
506 | 0 | case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14: |
507 | 0 | case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15: |
508 | 0 | addend = PG (addend); |
509 | | /* Fall through. */ |
510 | 0 | case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15: |
511 | 0 | case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC: |
512 | 0 | case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1: |
513 | 0 | value = value - addend; |
514 | 0 | break; |
515 | | |
516 | 0 | case BFD_RELOC_AARCH64_ADD_LO12: |
517 | 0 | case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC: |
518 | 0 | case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC: |
519 | 0 | case BFD_RELOC_AARCH64_LDST128_LO12: |
520 | 0 | case BFD_RELOC_AARCH64_LDST16_LO12: |
521 | 0 | case BFD_RELOC_AARCH64_LDST32_LO12: |
522 | 0 | case BFD_RELOC_AARCH64_LDST64_LO12: |
523 | 0 | case BFD_RELOC_AARCH64_LDST8_LO12: |
524 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADD: |
525 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12: |
526 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC: |
527 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12: |
528 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LDR: |
529 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC: |
530 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC: |
531 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: |
532 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC: |
533 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC: |
534 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC: |
535 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC: |
536 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC: |
537 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: |
538 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: |
539 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: |
540 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: |
541 | 0 | value = PG_OFFSET (value + addend); |
542 | 0 | break; |
543 | | |
544 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12: |
545 | 0 | value = value + addend; |
546 | 0 | break; |
547 | | |
548 | 0 | case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1: |
549 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1: |
550 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC: |
551 | 0 | value = (value + addend) & (bfd_vma) 0xffff0000; |
552 | 0 | break; |
553 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12: |
554 | | /* Mask off low 12bits, keep all other high bits, so that the later |
555 | | generic code could check whehter there is overflow. */ |
556 | 0 | value = (value + addend) & ~(bfd_vma) 0xfff; |
557 | 0 | break; |
558 | | |
559 | 0 | case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC: |
560 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0: |
561 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC: |
562 | 0 | value = (value + addend) & (bfd_vma) 0xffff; |
563 | 0 | break; |
564 | | |
565 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2: |
566 | 0 | value = (value + addend) & ~(bfd_vma) 0xffffffff; |
567 | 0 | value -= place & ~(bfd_vma) 0xffffffff; |
568 | 0 | break; |
569 | | |
570 | 0 | default: |
571 | 0 | break; |
572 | 0 | } |
573 | | |
574 | 0 | return value; |
575 | 0 | } |
576 | | |
577 | | /* Support for core dump NOTE sections. */ |
578 | | |
579 | | bool |
580 | | _bfd_aarch64_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) |
581 | 2 | { |
582 | 2 | int offset; |
583 | 2 | size_t size; |
584 | | |
585 | 2 | switch (note->descsz) |
586 | 2 | { |
587 | 2 | default: |
588 | 2 | return false; |
589 | | |
590 | 0 | case 392: /* sizeof(struct elf_prstatus) on Linux/arm64. */ |
591 | | /* pr_cursig */ |
592 | 0 | elf_tdata (abfd)->core->signal |
593 | 0 | = bfd_get_16 (abfd, note->descdata + 12); |
594 | | |
595 | | /* pr_pid */ |
596 | 0 | elf_tdata (abfd)->core->lwpid |
597 | 0 | = bfd_get_32 (abfd, note->descdata + 32); |
598 | | |
599 | | /* pr_reg */ |
600 | 0 | offset = 112; |
601 | 0 | size = 272; |
602 | |
|
603 | 0 | break; |
604 | 2 | } |
605 | | |
606 | | /* Make a ".reg/999" section. */ |
607 | 0 | return _bfd_elfcore_make_pseudosection (abfd, ".reg", |
608 | 0 | size, note->descpos + offset); |
609 | 2 | } |
610 | | |
611 | | bool |
612 | | _bfd_aarch64_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) |
613 | 1 | { |
614 | 1 | switch (note->descsz) |
615 | 1 | { |
616 | 1 | default: |
617 | 1 | return false; |
618 | | |
619 | 0 | case 136: /* This is sizeof(struct elf_prpsinfo) on Linux/aarch64. */ |
620 | 0 | elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 24); |
621 | 0 | elf_tdata (abfd)->core->program |
622 | 0 | = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16); |
623 | 0 | elf_tdata (abfd)->core->command |
624 | 0 | = _bfd_elfcore_strndup (abfd, note->descdata + 56, 80); |
625 | 1 | } |
626 | | |
627 | | /* Note that for some reason, a spurious space is tacked |
628 | | onto the end of the args in some (at least one anyway) |
629 | | implementations, so strip it off if it exists. */ |
630 | | |
631 | 0 | { |
632 | 0 | char *command = elf_tdata (abfd)->core->command; |
633 | 0 | int n = strlen (command); |
634 | |
|
635 | 0 | if (0 < n && command[n - 1] == ' ') |
636 | 0 | command[n - 1] = '\0'; |
637 | 0 | } |
638 | |
|
639 | 0 | return true; |
640 | 1 | } |
641 | | |
642 | | char * |
643 | | _bfd_aarch64_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, |
644 | | ...) |
645 | 0 | { |
646 | 0 | switch (note_type) |
647 | 0 | { |
648 | 0 | default: |
649 | 0 | return NULL; |
650 | | |
651 | 0 | case NT_PRPSINFO: |
652 | 0 | { |
653 | 0 | char data[136] ATTRIBUTE_NONSTRING; |
654 | 0 | va_list ap; |
655 | |
|
656 | 0 | va_start (ap, note_type); |
657 | 0 | memset (data, 0, sizeof (data)); |
658 | 0 | strncpy (data + 40, va_arg (ap, const char *), 16); |
659 | | #if GCC_VERSION == 8000 || GCC_VERSION == 8001 |
660 | | DIAGNOSTIC_PUSH; |
661 | | /* GCC 8.0 and 8.1 warn about 80 equals destination size with |
662 | | -Wstringop-truncation: |
663 | | https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85643 |
664 | | */ |
665 | | DIAGNOSTIC_IGNORE_STRINGOP_TRUNCATION; |
666 | | #endif |
667 | 0 | strncpy (data + 56, va_arg (ap, const char *), 80); |
668 | | #if GCC_VERSION == 8000 || GCC_VERSION == 8001 |
669 | | DIAGNOSTIC_POP; |
670 | | #endif |
671 | 0 | va_end (ap); |
672 | |
|
673 | 0 | return elfcore_write_note (abfd, buf, bufsiz, "CORE", |
674 | 0 | note_type, data, sizeof (data)); |
675 | 0 | } |
676 | | |
677 | 0 | case NT_PRSTATUS: |
678 | 0 | { |
679 | 0 | char data[392]; |
680 | 0 | va_list ap; |
681 | 0 | long pid; |
682 | 0 | int cursig; |
683 | 0 | const void *greg; |
684 | |
|
685 | 0 | va_start (ap, note_type); |
686 | 0 | memset (data, 0, sizeof (data)); |
687 | 0 | pid = va_arg (ap, long); |
688 | 0 | bfd_put_32 (abfd, pid, data + 32); |
689 | 0 | cursig = va_arg (ap, int); |
690 | 0 | bfd_put_16 (abfd, cursig, data + 12); |
691 | 0 | greg = va_arg (ap, const void *); |
692 | 0 | memcpy (data + 112, greg, 272); |
693 | 0 | va_end (ap); |
694 | |
|
695 | 0 | return elfcore_write_note (abfd, buf, bufsiz, "CORE", |
696 | 0 | note_type, data, sizeof (data)); |
697 | 0 | } |
698 | 0 | } |
699 | 0 | } |
700 | | |
701 | | typedef struct |
702 | | { |
703 | | bfd *pbfd; |
704 | | asection* sec; |
705 | | } bfd_search_result_t; |
706 | | |
707 | | static inline bool |
708 | | bfd_is_non_dynamic_elf_object (bfd *abfd, const struct elf_backend_data *out_be) |
709 | 0 | { |
710 | 0 | const struct elf_backend_data *in_be = get_elf_backend_data (abfd); |
711 | |
|
712 | 0 | return bfd_get_flavour (abfd) == bfd_target_elf_flavour |
713 | 0 | && bfd_count_sections (abfd) != 0 |
714 | 0 | && (abfd->flags & (DYNAMIC | BFD_PLUGIN | BFD_LINKER_CREATED)) == 0 |
715 | 0 | && out_be->elf_machine_code == in_be->elf_machine_code |
716 | 0 | && out_be->s->elfclass == in_be->s->elfclass; |
717 | 0 | } |
718 | | |
719 | | /* Find the first input bfd with GNU properties. |
720 | | If such an input is found, set found to true and return the relevant input. |
721 | | Otherwise, return the last input of bfd inputs. */ |
722 | | static bfd_search_result_t |
723 | | bfd_linear_search_one_with_gnu_property (struct bfd_link_info *info) |
724 | 0 | { |
725 | 0 | const struct elf_backend_data *be = get_elf_backend_data (info->output_bfd); |
726 | |
|
727 | 0 | bfd_search_result_t res = { |
728 | 0 | .pbfd = NULL, |
729 | 0 | .sec = NULL, |
730 | 0 | }; |
731 | |
|
732 | 0 | for (bfd *pbfd = info->input_bfds; pbfd != NULL; pbfd = pbfd->link.next) |
733 | 0 | if (bfd_is_non_dynamic_elf_object (pbfd, be)) |
734 | 0 | { |
735 | 0 | res.pbfd = pbfd; |
736 | | |
737 | | /* Does the input have a list of GNU properties ? */ |
738 | 0 | if (elf_properties (pbfd) != NULL) |
739 | 0 | break; |
740 | 0 | } |
741 | |
|
742 | 0 | if (res.pbfd != NULL) |
743 | 0 | res.sec = bfd_get_section_by_name (res.pbfd, NOTE_GNU_PROPERTY_SECTION_NAME); |
744 | |
|
745 | 0 | return res; |
746 | 0 | } |
747 | | |
748 | | /* Create a GNU property section for the given bfd input. */ |
749 | | static void |
750 | | _bfd_aarch64_elf_create_gnu_property_section (struct bfd_link_info *info, |
751 | | bfd *ebfd) |
752 | 0 | { |
753 | 0 | asection *sec; |
754 | 0 | sec = bfd_make_section_with_flags (ebfd, |
755 | 0 | NOTE_GNU_PROPERTY_SECTION_NAME, |
756 | 0 | (SEC_ALLOC |
757 | 0 | | SEC_LOAD |
758 | 0 | | SEC_IN_MEMORY |
759 | 0 | | SEC_READONLY |
760 | 0 | | SEC_HAS_CONTENTS |
761 | 0 | | SEC_DATA)); |
762 | 0 | unsigned align = (bfd_get_mach (ebfd) & bfd_mach_aarch64_ilp32) ? 2 : 3; |
763 | 0 | if (sec == NULL |
764 | 0 | || !bfd_set_section_alignment (sec, align)) |
765 | 0 | info->callbacks->fatal (_("%P: failed to create %s\n"), |
766 | 0 | NOTE_GNU_PROPERTY_SECTION_NAME); |
767 | | |
768 | 0 | elf_section_type (sec) = SHT_NOTE; |
769 | 0 | } |
770 | | |
771 | | static const int GNU_PROPERTY_ISSUES_MAX = 20; |
772 | | |
773 | | /* Report a summary of the issues met during the merge of the GNU properties, if |
774 | | the number of issues goes above GNU_PROPERTY_ISSUES_MAX. */ |
775 | | static void |
776 | | _bfd_aarch64_report_summary_merge_issues (struct bfd_link_info *info) |
777 | 0 | { |
778 | 0 | const struct elf_aarch64_obj_tdata * tdata |
779 | 0 | = elf_aarch64_tdata (info->output_bfd); |
780 | |
|
781 | 0 | if (tdata->n_bti_issues > GNU_PROPERTY_ISSUES_MAX |
782 | 0 | && tdata->sw_protections.bti_report != MARKING_NONE) |
783 | 0 | { |
784 | 0 | const char *msg |
785 | 0 | = (tdata->sw_protections.bti_report == MARKING_ERROR) |
786 | 0 | ? _("%Xerror: found a total of %d inputs incompatible with " |
787 | 0 | "BTI requirements.\n") |
788 | 0 | : _("warning: found a total of %d inputs incompatible with " |
789 | 0 | "BTI requirements.\n"); |
790 | 0 | info->callbacks->einfo (msg, tdata->n_bti_issues); |
791 | 0 | } |
792 | |
|
793 | 0 | if (tdata->n_gcs_issues > GNU_PROPERTY_ISSUES_MAX |
794 | 0 | && tdata->sw_protections.gcs_report != MARKING_NONE) |
795 | 0 | { |
796 | 0 | const char *msg |
797 | 0 | = (tdata->sw_protections.gcs_report == MARKING_ERROR) |
798 | 0 | ? _("%Xerror: found a total of %d inputs incompatible with " |
799 | 0 | "GCS requirements.\n") |
800 | 0 | : _("warning: found a total of %d inputs incompatible with " |
801 | 0 | "GCS requirements.\n"); |
802 | 0 | info->callbacks->einfo (msg, tdata->n_gcs_issues); |
803 | 0 | } |
804 | |
|
805 | 0 | if (tdata->n_gcs_dynamic_issues > GNU_PROPERTY_ISSUES_MAX |
806 | 0 | && tdata->sw_protections.gcs_report_dynamic != MARKING_NONE) |
807 | 0 | { |
808 | 0 | const char *msg |
809 | 0 | = (tdata->sw_protections.gcs_report_dynamic == MARKING_ERROR) |
810 | 0 | ? _("%Xerror: found a total of %d dynamically-linked objects " |
811 | 0 | "incompatible with GCS requirements.\n") |
812 | 0 | : _("warning: found a total of %d dynamically-linked objects " |
813 | 0 | "incompatible with GCS requirements.\n"); |
814 | 0 | info->callbacks->einfo (msg, tdata->n_gcs_dynamic_issues); |
815 | 0 | } |
816 | 0 | } |
817 | | |
818 | | /* Perform a look-up of a property in an unsorted list of properties. This is |
819 | | useful when the list of properties of an object has not been sorted yet. */ |
820 | | static uint32_t |
821 | | _bfd_aarch64_prop_linear_lookup (elf_property_list *properties, |
822 | | unsigned int pr_type) |
823 | 0 | { |
824 | 0 | for (elf_property_list *p = properties; p != NULL; p = p->next) |
825 | 0 | if (p->property.pr_type == pr_type) |
826 | 0 | return p->property.u.number; |
827 | 0 | return 0; |
828 | 0 | } |
829 | | |
830 | | /* Compare the GNU properties of the current dynamic object, with the ones of |
831 | | the output BFD. Today, we only care about GCS feature stored in |
832 | | GNU_PROPERTY_AARCH64_FEATURE_1. */ |
833 | | static void |
834 | | _bfd_aarch64_compare_dynamic_obj_prop_against_outprop( |
835 | | struct bfd_link_info *info, |
836 | | const uint32_t outprop, |
837 | | bfd *pbfd) |
838 | 0 | { |
839 | 0 | if (!(outprop & GNU_PROPERTY_AARCH64_FEATURE_1_GCS)) |
840 | 0 | return; |
841 | | |
842 | 0 | const uint32_t dyn_obj_aarch64_feature_prop = |
843 | 0 | _bfd_aarch64_prop_linear_lookup (elf_properties (pbfd), |
844 | 0 | GNU_PROPERTY_AARCH64_FEATURE_1_AND); |
845 | 0 | if (!(dyn_obj_aarch64_feature_prop & GNU_PROPERTY_AARCH64_FEATURE_1_GCS)) |
846 | 0 | _bfd_aarch64_elf_check_gcs_report (info, pbfd); |
847 | 0 | } |
848 | | |
849 | | /* Check compatibility between the GNU properties of the ouput BFD and the |
850 | | linked dynamic objects. */ |
851 | | static void |
852 | | _bfd_aarch64_elf_check_gnu_properties_linked_dynamic_objects ( |
853 | | struct bfd_link_info * info, |
854 | | const uint32_t outprop) |
855 | 0 | { |
856 | 0 | const struct elf_backend_data *bed = get_elf_backend_data (info->output_bfd); |
857 | 0 | const int elf_machine_code = bed->elf_machine_code; |
858 | 0 | const unsigned int elfclass = bed->s->elfclass; |
859 | |
|
860 | 0 | for (bfd *pbfd = info->input_bfds; pbfd != NULL; pbfd = pbfd->link.next) |
861 | | /* Ignore GNU properties from non-ELF objects or ELF objects with different |
862 | | machine code. */ |
863 | 0 | if ((pbfd->flags & DYNAMIC) != 0 |
864 | 0 | && (bfd_get_flavour (pbfd) == bfd_target_elf_flavour) |
865 | 0 | && (get_elf_backend_data (pbfd)->elf_machine_code == elf_machine_code) |
866 | 0 | && (get_elf_backend_data (pbfd)->s->elfclass == elfclass)) |
867 | 0 | _bfd_aarch64_compare_dynamic_obj_prop_against_outprop(info, outprop, |
868 | 0 | pbfd); |
869 | 0 | } |
870 | | |
871 | | /* Find the first input bfd with GNU property and merge it with GPROP. If no |
872 | | such input is found, add it to a new section at the last input. Update |
873 | | GPROP accordingly. */ |
874 | | bfd * |
875 | | _bfd_aarch64_elf_link_setup_gnu_properties (struct bfd_link_info *info) |
876 | 0 | { |
877 | 0 | struct elf_aarch64_obj_tdata *tdata = elf_aarch64_tdata (info->output_bfd); |
878 | 0 | uint32_t outprop = tdata->gnu_property_aarch64_feature_1_and; |
879 | |
|
880 | 0 | bfd_search_result_t res = bfd_linear_search_one_with_gnu_property (info); |
881 | | |
882 | | /* If ebfd != NULL it is either an input with property note or the last input. |
883 | | Either way if we have an output GNU property that was provided, we should |
884 | | add it (by creating a section if needed). */ |
885 | 0 | if (res.pbfd != NULL) |
886 | 0 | { |
887 | | /* If no GNU property note section was found, create one. |
888 | | |
889 | | Note: If there is no .gnu.note.property section, we might think that |
890 | | elf_properties (res.pbfd) is always NULL. However, this is not always |
891 | | true. In PR23900: old linkers were treating .note.gnu.property as a |
892 | | generic note section, so old objects might contain properties inside |
893 | | .note instead of .note.gnu.property. In this case, the section won't be |
894 | | detected but the properties are still parsed. Consequently, |
895 | | elf_properties (res.pbfd) is populated and different from NULL (see |
896 | | https://sourceware.org/bugzilla/show_bug.cgi?id=23900 for more |
897 | | details). */ |
898 | 0 | if (res.sec == NULL && elf_properties (res.pbfd) == NULL) |
899 | 0 | _bfd_aarch64_elf_create_gnu_property_section (info, res.pbfd); |
900 | | |
901 | | /* Merge the found input property with output properties. Note: if no |
902 | | property was found, _bfd_elf_get_property will create one. */ |
903 | 0 | elf_property *prop = |
904 | 0 | _bfd_elf_get_property (res.pbfd, |
905 | 0 | GNU_PROPERTY_AARCH64_FEATURE_1_AND, |
906 | 0 | 4); |
907 | | |
908 | | /* Check for a feature mismatch and report issue (if any) before this |
909 | | information get lost as the value of ebfd will be overriden with |
910 | | outprop. */ |
911 | 0 | if ((outprop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) |
912 | 0 | && !(prop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) |
913 | 0 | _bfd_aarch64_elf_check_bti_report (info, res.pbfd); |
914 | |
|
915 | 0 | if (tdata->sw_protections.gcs_type == GCS_NEVER) |
916 | 0 | prop->u.number &= ~GNU_PROPERTY_AARCH64_FEATURE_1_GCS; |
917 | 0 | else if ((outprop & GNU_PROPERTY_AARCH64_FEATURE_1_GCS) |
918 | 0 | && !(prop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_GCS)) |
919 | 0 | _bfd_aarch64_elf_check_gcs_report (info, res.pbfd); |
920 | |
|
921 | 0 | prop->u.number |= outprop; |
922 | 0 | if (prop->u.number == 0) |
923 | 0 | prop->pr_kind = property_remove; |
924 | 0 | else |
925 | 0 | prop->pr_kind = property_number; |
926 | 0 | } |
927 | | |
928 | | /* Set up generic GNU properties, and merge them with the backend-specific |
929 | | ones (if any). pbfd points to the first relocatable ELF input with |
930 | | GNU properties (if found). */ |
931 | 0 | bfd *pbfd = _bfd_elf_link_setup_gnu_properties (info); |
932 | |
|
933 | 0 | if (pbfd != NULL) |
934 | 0 | { |
935 | 0 | elf_property_list *p; |
936 | 0 | elf_property_list *plist = elf_properties (pbfd); |
937 | | |
938 | | /* If pbfd has any GNU_PROPERTY_AARCH64_FEATURE_1_AND properties, update |
939 | | outprop accordingly. */ |
940 | 0 | if ((p = _bfd_elf_find_property (plist, |
941 | 0 | GNU_PROPERTY_AARCH64_FEATURE_1_AND, NULL)) |
942 | 0 | != NULL) |
943 | 0 | outprop = p->property.u.number |
944 | 0 | & (GNU_PROPERTY_AARCH64_FEATURE_1_BTI |
945 | 0 | | GNU_PROPERTY_AARCH64_FEATURE_1_PAC |
946 | 0 | | GNU_PROPERTY_AARCH64_FEATURE_1_GCS); |
947 | 0 | } |
948 | |
|
949 | 0 | tdata->gnu_property_aarch64_feature_1_and = outprop; |
950 | |
|
951 | 0 | _bfd_aarch64_elf_check_gnu_properties_linked_dynamic_objects (info, outprop); |
952 | |
|
953 | 0 | _bfd_aarch64_report_summary_merge_issues (info); |
954 | |
|
955 | 0 | return pbfd; |
956 | 0 | } |
957 | | |
958 | | /* Define elf_backend_parse_gnu_properties for AArch64. */ |
959 | | enum elf_property_kind |
960 | | _bfd_aarch64_elf_parse_gnu_properties (bfd *abfd, unsigned int type, |
961 | | bfd_byte *ptr, unsigned int datasz) |
962 | 0 | { |
963 | 0 | elf_property *prop; |
964 | |
|
965 | 0 | switch (type) |
966 | 0 | { |
967 | 0 | case GNU_PROPERTY_AARCH64_FEATURE_1_AND: |
968 | 0 | if (datasz != 4) |
969 | 0 | { |
970 | 0 | _bfd_error_handler |
971 | 0 | ( _("error: %pB: <corrupt AArch64 used size: 0x%x>"), |
972 | 0 | abfd, datasz); |
973 | 0 | return property_corrupt; |
974 | 0 | } |
975 | 0 | prop = _bfd_elf_get_property (abfd, type, datasz); |
976 | | /* Merge AArch64 feature properties together if they are declared in |
977 | | different AARCH64_FEATURE_1_AND properties. */ |
978 | 0 | prop->u.number |= bfd_h_get_32 (abfd, ptr); |
979 | 0 | prop->pr_kind = property_number; |
980 | 0 | break; |
981 | | |
982 | 0 | default: |
983 | 0 | return property_ignored; |
984 | 0 | } |
985 | | |
986 | 0 | return property_number; |
987 | 0 | } |
988 | | |
989 | | /* Merge AArch64 GNU property BPROP with APROP also accounting for OUTPROP. |
990 | | If APROP isn't NULL, merge it with BPROP and/or OUTPROP. Vice-versa if BROP |
991 | | isn't NULL. Return TRUE if there is any update to APROP or if BPROP should |
992 | | be merge with ABFD. */ |
993 | | bool |
994 | | _bfd_aarch64_elf_merge_gnu_properties (struct bfd_link_info *info |
995 | | ATTRIBUTE_UNUSED, |
996 | | bfd *abfd ATTRIBUTE_UNUSED, |
997 | | elf_property *aprop, |
998 | | elf_property *bprop, |
999 | | uint32_t outprop) |
1000 | 0 | { |
1001 | 0 | unsigned int orig_number; |
1002 | 0 | bool updated = false; |
1003 | 0 | unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type; |
1004 | |
|
1005 | 0 | switch (pr_type) |
1006 | 0 | { |
1007 | 0 | case GNU_PROPERTY_AARCH64_FEATURE_1_AND: |
1008 | 0 | { |
1009 | 0 | aarch64_gcs_type gcs_type |
1010 | 0 | = elf_aarch64_tdata (info->output_bfd)->sw_protections.gcs_type; |
1011 | | /* OUTPROP does not contain GCS for GCS_NEVER. We only need to make sure |
1012 | | that APROP does not contain GCS as well. |
1013 | | Notes: |
1014 | | - if BPROP contains GCS and APROP is not null, it is zeroed by the |
1015 | | AND with APROP. |
1016 | | - if BPROP contains GCS and APROP is null, it is overwritten with |
1017 | | OUTPROP as the AND with APROP would have been equivalent to zeroing |
1018 | | BPROP. */ |
1019 | 0 | if (gcs_type == GCS_NEVER && aprop != NULL) |
1020 | 0 | aprop->u.number &= ~GNU_PROPERTY_AARCH64_FEATURE_1_GCS; |
1021 | |
|
1022 | 0 | if (aprop != NULL && bprop != NULL) |
1023 | 0 | { |
1024 | 0 | orig_number = aprop->u.number; |
1025 | 0 | aprop->u.number = (orig_number & bprop->u.number) | outprop; |
1026 | 0 | updated = orig_number != aprop->u.number; |
1027 | | /* Remove the property if all feature bits are cleared. */ |
1028 | 0 | if (aprop->u.number == 0) |
1029 | 0 | aprop->pr_kind = property_remove; |
1030 | 0 | break; |
1031 | 0 | } |
1032 | | /* If either is NULL, the AND would be 0 so, if there is |
1033 | | any OUTPROP, assign it to the input that is not NULL. */ |
1034 | 0 | if (outprop) |
1035 | 0 | { |
1036 | 0 | if (aprop != NULL) |
1037 | 0 | { |
1038 | 0 | orig_number = aprop->u.number; |
1039 | 0 | aprop->u.number = outprop; |
1040 | 0 | updated = orig_number != aprop->u.number; |
1041 | 0 | } |
1042 | 0 | else |
1043 | 0 | { |
1044 | 0 | bprop->u.number = outprop; |
1045 | 0 | updated = true; |
1046 | 0 | } |
1047 | 0 | } |
1048 | | /* No OUTPROP and BPROP is NULL, so remove APROP. */ |
1049 | 0 | else if (aprop != NULL) |
1050 | 0 | { |
1051 | 0 | aprop->pr_kind = property_remove; |
1052 | 0 | updated = true; |
1053 | 0 | } |
1054 | 0 | } |
1055 | 0 | break; |
1056 | | |
1057 | 0 | default: |
1058 | 0 | abort (); |
1059 | 0 | } |
1060 | | |
1061 | 0 | return updated; |
1062 | 0 | } |
1063 | | |
1064 | | /* Fix up AArch64 GNU properties. */ |
1065 | | void |
1066 | | _bfd_aarch64_elf_link_fixup_gnu_properties |
1067 | | (struct bfd_link_info *info ATTRIBUTE_UNUSED, |
1068 | | elf_property_list **listp) |
1069 | 0 | { |
1070 | 0 | elf_property_list *p, *prev; |
1071 | |
|
1072 | 0 | for (p = *listp, prev = *listp; p; p = p->next) |
1073 | 0 | { |
1074 | 0 | unsigned int type = p->property.pr_type; |
1075 | 0 | if (type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) |
1076 | 0 | { |
1077 | 0 | if (p->property.pr_kind == property_remove) |
1078 | 0 | { |
1079 | | /* Remove empty property. */ |
1080 | 0 | if (prev == p) |
1081 | 0 | { |
1082 | 0 | *listp = p->next; |
1083 | 0 | prev = *listp; |
1084 | 0 | } |
1085 | 0 | else |
1086 | 0 | prev->next = p->next; |
1087 | 0 | continue; |
1088 | 0 | } |
1089 | 0 | prev = p; |
1090 | 0 | } |
1091 | 0 | else if (type > GNU_PROPERTY_HIPROC) |
1092 | 0 | { |
1093 | | /* The property list is sorted in order of type. */ |
1094 | 0 | break; |
1095 | 0 | } |
1096 | 0 | } |
1097 | 0 | } |
1098 | | |
1099 | | /* Check AArch64 BTI report. */ |
1100 | | void |
1101 | | _bfd_aarch64_elf_check_bti_report (struct bfd_link_info *info, bfd *ebfd) |
1102 | 0 | { |
1103 | 0 | struct elf_aarch64_obj_tdata *tdata = elf_aarch64_tdata (info->output_bfd); |
1104 | |
|
1105 | 0 | if (tdata->sw_protections.bti_report == MARKING_NONE) |
1106 | 0 | return; |
1107 | | |
1108 | 0 | ++tdata->n_bti_issues; |
1109 | |
|
1110 | 0 | if (tdata->n_bti_issues > GNU_PROPERTY_ISSUES_MAX) |
1111 | 0 | return; |
1112 | | |
1113 | 0 | const char *msg |
1114 | 0 | = (tdata->sw_protections.bti_report == MARKING_WARN) |
1115 | 0 | ? _("%pB: warning: BTI is required by -z force-bti, but this input object " |
1116 | 0 | "file lacks the necessary property note.\n") |
1117 | 0 | : _("%X%pB: error: BTI is required by -z force-bti, but this input object " |
1118 | 0 | "file lacks the necessary property note.\n"); |
1119 | |
|
1120 | 0 | info->callbacks->einfo (msg, ebfd); |
1121 | 0 | } |
1122 | | |
1123 | | void |
1124 | | _bfd_aarch64_elf_check_gcs_report (struct bfd_link_info *info, bfd *ebfd) |
1125 | 0 | { |
1126 | 0 | struct elf_aarch64_obj_tdata *tdata = elf_aarch64_tdata (info->output_bfd); |
1127 | 0 | bool dynamic_obj = (ebfd->flags & DYNAMIC) != 0; |
1128 | |
|
1129 | 0 | if (dynamic_obj) |
1130 | 0 | { |
1131 | 0 | if (tdata->sw_protections.gcs_report_dynamic == MARKING_NONE) |
1132 | 0 | return; |
1133 | 0 | ++tdata->n_gcs_dynamic_issues; |
1134 | 0 | if (tdata->n_gcs_dynamic_issues > GNU_PROPERTY_ISSUES_MAX) |
1135 | 0 | return; |
1136 | 0 | } |
1137 | 0 | else |
1138 | 0 | { |
1139 | 0 | if (tdata->sw_protections.gcs_report == MARKING_NONE) |
1140 | 0 | return; |
1141 | 0 | ++tdata->n_gcs_issues; |
1142 | 0 | if (tdata->n_gcs_issues > GNU_PROPERTY_ISSUES_MAX) |
1143 | 0 | return; |
1144 | 0 | } |
1145 | | |
1146 | 0 | const char *msg; |
1147 | 0 | if (dynamic_obj) |
1148 | 0 | msg = (tdata->sw_protections.gcs_report_dynamic == MARKING_WARN) |
1149 | 0 | ? _("%pB: warning: GCS is required by -z gcs, but this shared library " |
1150 | 0 | "lacks the necessary property note. The dynamic loader might not " |
1151 | 0 | "enable GCS or refuse to load the program unless all the shared " |
1152 | 0 | "library dependencies have the GCS marking.\n") |
1153 | 0 | : _("%X%pB: error: GCS is required by -z gcs, but this shared library " |
1154 | 0 | "lacks the necessary property note. The dynamic loader might not " |
1155 | 0 | "enable GCS or refuse to load the program unless all the shared " |
1156 | 0 | "library dependencies have the GCS marking.\n"); |
1157 | 0 | else |
1158 | 0 | msg = (tdata->sw_protections.gcs_report == MARKING_WARN) |
1159 | 0 | ? _("%pB: warning: GCS is required by -z gcs, but this input object file " |
1160 | 0 | "lacks the necessary property note.\n") |
1161 | 0 | : _("%X%pB: error: GCS is required by -z gcs, but this input object file " |
1162 | 0 | "lacks the necessary property note.\n"); |
1163 | |
|
1164 | 0 | info->callbacks->einfo (msg, ebfd); |
1165 | 0 | } |