/src/binutils-gdb/bfd/elfxx-aarch64.c
Line | Count | Source |
1 | | /* AArch64-specific support for ELF. |
2 | | Copyright (C) 2009-2026 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 "elf/aarch64.h" |
25 | | #include "elfxx-aarch64.h" |
26 | | #include "libbfd.h" |
27 | | #include "libiberty.h" |
28 | | #include <stdarg.h> |
29 | | #include <string.h> |
30 | | |
31 | 0 | #define MASK(n) ((1u << (n)) - 1) |
32 | | |
33 | | /* Sign-extend VALUE, which has the indicated number of BITS. */ |
34 | | |
35 | | bfd_signed_vma |
36 | | _bfd_aarch64_sign_extend (bfd_vma value, int bits) |
37 | 0 | { |
38 | 0 | if (value & ((bfd_vma) 1 << (bits - 1))) |
39 | | /* VALUE is negative. */ |
40 | 0 | value |= ((bfd_vma) - 1) << bits; |
41 | |
|
42 | 0 | return value; |
43 | 0 | } |
44 | | |
45 | | /* Decode the IMM field of ADRP. */ |
46 | | |
47 | | uint32_t |
48 | | _bfd_aarch64_decode_adrp_imm (uint32_t insn) |
49 | 0 | { |
50 | 0 | return (((insn >> 5) & MASK (19)) << 2) | ((insn >> 29) & MASK (2)); |
51 | 0 | } |
52 | | |
53 | | /* Reencode the imm field of add immediate. */ |
54 | | static inline uint32_t |
55 | | reencode_add_imm (uint32_t insn, uint32_t imm) |
56 | 0 | { |
57 | 0 | return (insn & ~(MASK (12) << 10)) | ((imm & MASK (12)) << 10); |
58 | 0 | } |
59 | | |
60 | | /* Reencode the IMM field of ADR. */ |
61 | | |
62 | | uint32_t |
63 | | _bfd_aarch64_reencode_adr_imm (uint32_t insn, uint32_t imm) |
64 | 0 | { |
65 | 0 | return (insn & ~((MASK (2) << 29) | (MASK (19) << 5))) |
66 | 0 | | ((imm & MASK (2)) << 29) | ((imm & (MASK (19) << 2)) << 3); |
67 | 0 | } |
68 | | |
69 | | /* Reencode the imm field of ld/st pos immediate. */ |
70 | | static inline uint32_t |
71 | | reencode_ldst_pos_imm (uint32_t insn, uint32_t imm) |
72 | 0 | { |
73 | 0 | return (insn & ~(MASK (12) << 10)) | ((imm & MASK (12)) << 10); |
74 | 0 | } |
75 | | |
76 | | /* Encode the 26-bit offset of unconditional branch. */ |
77 | | static inline uint32_t |
78 | | reencode_branch_ofs_26 (uint32_t insn, uint32_t ofs) |
79 | 0 | { |
80 | 0 | return (insn & ~MASK (26)) | (ofs & MASK (26)); |
81 | 0 | } |
82 | | |
83 | | /* Encode the 19-bit offset of conditional branch and compare & branch. */ |
84 | | static inline uint32_t |
85 | | reencode_cond_branch_ofs_19 (uint32_t insn, uint32_t ofs) |
86 | 0 | { |
87 | 0 | return (insn & ~(MASK (19) << 5)) | ((ofs & MASK (19)) << 5); |
88 | 0 | } |
89 | | |
90 | | /* Decode the 19-bit offset of load literal. */ |
91 | | static inline uint32_t |
92 | | reencode_ld_lit_ofs_19 (uint32_t insn, uint32_t ofs) |
93 | 0 | { |
94 | 0 | return (insn & ~(MASK (19) << 5)) | ((ofs & MASK (19)) << 5); |
95 | 0 | } |
96 | | |
97 | | /* Encode the 14-bit offset of test & branch. */ |
98 | | static inline uint32_t |
99 | | reencode_tst_branch_ofs_14 (uint32_t insn, uint32_t ofs) |
100 | 0 | { |
101 | 0 | return (insn & ~(MASK (14) << 5)) | ((ofs & MASK (14)) << 5); |
102 | 0 | } |
103 | | |
104 | | /* Reencode the imm field of move wide. */ |
105 | | static inline uint32_t |
106 | | reencode_movw_imm (uint32_t insn, uint32_t imm) |
107 | 0 | { |
108 | 0 | return (insn & ~(MASK (16) << 5)) | ((imm & MASK (16)) << 5); |
109 | 0 | } |
110 | | |
111 | | /* Reencode mov[zn] to movz. */ |
112 | | static inline uint32_t |
113 | | reencode_movzn_to_movz (uint32_t opcode) |
114 | 0 | { |
115 | 0 | return opcode | (1 << 30); |
116 | 0 | } |
117 | | |
118 | | /* Reencode mov[zn] to movn. */ |
119 | | static inline uint32_t |
120 | | reencode_movzn_to_movn (uint32_t opcode) |
121 | 0 | { |
122 | 0 | return opcode & ~(1 << 30); |
123 | 0 | } |
124 | | |
125 | | /* Return non-zero if the indicated VALUE has overflowed the maximum |
126 | | range expressible by a unsigned number with the indicated number of |
127 | | BITS. */ |
128 | | |
129 | | static bfd_reloc_status_type |
130 | | aarch64_unsigned_overflow (bfd_vma value, unsigned int bits) |
131 | 0 | { |
132 | 0 | bfd_vma lim; |
133 | 0 | if (bits >= sizeof (bfd_vma) * 8) |
134 | 0 | return bfd_reloc_ok; |
135 | 0 | lim = (bfd_vma) 1 << bits; |
136 | 0 | if (value >= lim) |
137 | 0 | return bfd_reloc_overflow; |
138 | 0 | return bfd_reloc_ok; |
139 | 0 | } |
140 | | |
141 | | /* Return non-zero if the indicated VALUE has overflowed the maximum |
142 | | range expressible by an signed number with the indicated number of |
143 | | BITS. */ |
144 | | |
145 | | static bfd_reloc_status_type |
146 | | aarch64_signed_overflow (bfd_vma value, unsigned int bits) |
147 | 0 | { |
148 | 0 | bfd_signed_vma svalue = (bfd_signed_vma) value; |
149 | 0 | bfd_signed_vma lim; |
150 | |
|
151 | 0 | if (bits >= sizeof (bfd_vma) * 8) |
152 | 0 | return bfd_reloc_ok; |
153 | 0 | lim = (bfd_signed_vma) 1 << (bits - 1); |
154 | 0 | if (svalue < -lim || svalue >= lim) |
155 | 0 | return bfd_reloc_overflow; |
156 | 0 | return bfd_reloc_ok; |
157 | 0 | } |
158 | | |
159 | | /* Insert the addend/value into the instruction or data object being |
160 | | relocated. */ |
161 | | bfd_reloc_status_type |
162 | | _bfd_aarch64_elf_put_addend (bfd *abfd, |
163 | | bfd_byte *address, bfd_reloc_code_real_type r_type, |
164 | | reloc_howto_type *howto, bfd_signed_vma addend) |
165 | 0 | { |
166 | 0 | bfd_reloc_status_type status = bfd_reloc_ok; |
167 | 0 | bfd_signed_vma old_addend = addend; |
168 | 0 | bfd_vma contents; |
169 | 0 | int size; |
170 | |
|
171 | 0 | size = bfd_get_reloc_size (howto); |
172 | 0 | switch (size) |
173 | 0 | { |
174 | 0 | case 0: |
175 | 0 | return status; |
176 | 0 | case 2: |
177 | 0 | contents = bfd_get_16 (abfd, address); |
178 | 0 | break; |
179 | 0 | case 4: |
180 | 0 | if (howto->src_mask != 0xffffffff) |
181 | | /* Must be 32-bit instruction, always little-endian. */ |
182 | 0 | contents = bfd_getl32 (address); |
183 | 0 | else |
184 | | /* Must be 32-bit data (endianness dependent). */ |
185 | 0 | contents = bfd_get_32 (abfd, address); |
186 | 0 | break; |
187 | 0 | case 8: |
188 | 0 | contents = bfd_get_64 (abfd, address); |
189 | 0 | break; |
190 | 0 | default: |
191 | 0 | abort (); |
192 | 0 | } |
193 | | |
194 | 0 | switch (howto->complain_on_overflow) |
195 | 0 | { |
196 | 0 | case complain_overflow_dont: |
197 | 0 | break; |
198 | 0 | case complain_overflow_signed: |
199 | 0 | status = aarch64_signed_overflow (addend, |
200 | 0 | howto->bitsize + howto->rightshift); |
201 | 0 | break; |
202 | 0 | case complain_overflow_unsigned: |
203 | 0 | status = aarch64_unsigned_overflow (addend, |
204 | 0 | howto->bitsize + howto->rightshift); |
205 | 0 | break; |
206 | 0 | case complain_overflow_bitfield: |
207 | 0 | default: |
208 | 0 | abort (); |
209 | 0 | } |
210 | | |
211 | 0 | addend >>= howto->rightshift; |
212 | |
|
213 | 0 | switch (r_type) |
214 | 0 | { |
215 | 0 | case BFD_RELOC_AARCH64_CALL26: |
216 | 0 | case BFD_RELOC_AARCH64_JUMP26: |
217 | 0 | contents = reencode_branch_ofs_26 (contents, addend); |
218 | 0 | break; |
219 | | |
220 | 0 | case BFD_RELOC_AARCH64_BRANCH19: |
221 | 0 | contents = reencode_cond_branch_ofs_19 (contents, addend); |
222 | 0 | break; |
223 | | |
224 | 0 | case BFD_RELOC_AARCH64_TSTBR14: |
225 | 0 | contents = reencode_tst_branch_ofs_14 (contents, addend); |
226 | 0 | break; |
227 | | |
228 | 0 | case BFD_RELOC_AARCH64_GOT_LD_PREL19: |
229 | 0 | case BFD_RELOC_AARCH64_LD_LO19_PCREL: |
230 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19: |
231 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19: |
232 | 0 | if (old_addend & ((1 << howto->rightshift) - 1)) |
233 | 0 | return bfd_reloc_overflow; |
234 | 0 | contents = reencode_ld_lit_ofs_19 (contents, addend); |
235 | 0 | break; |
236 | | |
237 | 0 | case BFD_RELOC_AARCH64_TLSDESC_CALL: |
238 | 0 | break; |
239 | | |
240 | 0 | case BFD_RELOC_AARCH64_ADR_GOT_PAGE: |
241 | 0 | case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL: |
242 | 0 | case BFD_RELOC_AARCH64_ADR_HI21_PCREL: |
243 | 0 | case BFD_RELOC_AARCH64_ADR_LO21_PCREL: |
244 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21: |
245 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21: |
246 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21: |
247 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21: |
248 | 0 | case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: |
249 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21: |
250 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21: |
251 | 0 | contents = _bfd_aarch64_reencode_adr_imm (contents, addend); |
252 | 0 | break; |
253 | | |
254 | 0 | case BFD_RELOC_AARCH64_ADD_LO12: |
255 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12: |
256 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC: |
257 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_HI12: |
258 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12: |
259 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: |
260 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC: |
261 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12: |
262 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12: |
263 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC: |
264 | | /* Corresponds to: add rd, rn, #uimm12 to provide the low order |
265 | | 12 bits of the page offset following |
266 | | BFD_RELOC_AARCH64_ADR_HI21_PCREL which computes the |
267 | | (pc-relative) page base. */ |
268 | 0 | contents = reencode_add_imm (contents, addend); |
269 | 0 | break; |
270 | | |
271 | 0 | case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14: |
272 | 0 | case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC: |
273 | 0 | case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15: |
274 | 0 | case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15: |
275 | 0 | case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC: |
276 | 0 | case BFD_RELOC_AARCH64_LDST128_LO12: |
277 | 0 | case BFD_RELOC_AARCH64_LDST16_LO12: |
278 | 0 | case BFD_RELOC_AARCH64_LDST32_LO12: |
279 | 0 | case BFD_RELOC_AARCH64_LDST64_LO12: |
280 | 0 | case BFD_RELOC_AARCH64_LDST8_LO12: |
281 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC: |
282 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12: |
283 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC: |
284 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: |
285 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12: |
286 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC: |
287 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12: |
288 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC: |
289 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12: |
290 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC: |
291 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12: |
292 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC: |
293 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12: |
294 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: |
295 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12: |
296 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: |
297 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12: |
298 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: |
299 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12: |
300 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: |
301 | 0 | if (old_addend & ((1 << howto->rightshift) - 1)) |
302 | 0 | return bfd_reloc_overflow; |
303 | | /* Used for ldr*|str* rt, [rn, #uimm12] to provide the low order |
304 | | 12 bits address offset. */ |
305 | 0 | contents = reencode_ldst_pos_imm (contents, addend); |
306 | 0 | break; |
307 | | |
308 | | /* Group relocations to create high bits of a 16, 32, 48 or 64 |
309 | | bit signed data or abs address inline. Will change |
310 | | instruction to MOVN or MOVZ depending on sign of calculated |
311 | | value. */ |
312 | | |
313 | 0 | case BFD_RELOC_AARCH64_MOVW_G0_S: |
314 | 0 | case BFD_RELOC_AARCH64_MOVW_G1_S: |
315 | 0 | case BFD_RELOC_AARCH64_MOVW_G2_S: |
316 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G0: |
317 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G1: |
318 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G2: |
319 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G3: |
320 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0: |
321 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1: |
322 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2: |
323 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0: |
324 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1: |
325 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2: |
326 | | /* NOTE: We can only come here with movz or movn. */ |
327 | 0 | if (addend < 0) |
328 | 0 | { |
329 | | /* Force use of MOVN. */ |
330 | 0 | addend = ~addend; |
331 | 0 | contents = reencode_movzn_to_movn (contents); |
332 | 0 | } |
333 | 0 | else |
334 | 0 | { |
335 | | /* Force use of MOVZ. */ |
336 | 0 | contents = reencode_movzn_to_movz (contents); |
337 | 0 | } |
338 | | /* Fall through. */ |
339 | | |
340 | | /* Group relocations to create a 16, 32, 48 or 64 bit unsigned |
341 | | data or abs address inline. */ |
342 | |
|
343 | 0 | case BFD_RELOC_AARCH64_MOVW_G0: |
344 | 0 | case BFD_RELOC_AARCH64_MOVW_G0_NC: |
345 | 0 | case BFD_RELOC_AARCH64_MOVW_G1: |
346 | 0 | case BFD_RELOC_AARCH64_MOVW_G1_NC: |
347 | 0 | case BFD_RELOC_AARCH64_MOVW_G2: |
348 | 0 | case BFD_RELOC_AARCH64_MOVW_G2_NC: |
349 | 0 | case BFD_RELOC_AARCH64_MOVW_G3: |
350 | 0 | case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC: |
351 | 0 | case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1: |
352 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G0_NC: |
353 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G1_NC: |
354 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G2_NC: |
355 | 0 | case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC: |
356 | 0 | case BFD_RELOC_AARCH64_TLSDESC_OFF_G1: |
357 | 0 | case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC: |
358 | 0 | case BFD_RELOC_AARCH64_TLSGD_MOVW_G1: |
359 | 0 | case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC: |
360 | 0 | case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1: |
361 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: |
362 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC: |
363 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC: |
364 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC: |
365 | 0 | contents = reencode_movw_imm (contents, addend); |
366 | 0 | break; |
367 | | |
368 | 0 | default: |
369 | | /* Repack simple data */ |
370 | 0 | if (howto->dst_mask & (howto->dst_mask + 1)) |
371 | 0 | return bfd_reloc_notsupported; |
372 | | |
373 | 0 | contents = ((contents & ~howto->dst_mask) | (addend & howto->dst_mask)); |
374 | 0 | break; |
375 | 0 | } |
376 | | |
377 | 0 | switch (size) |
378 | 0 | { |
379 | 0 | case 2: |
380 | 0 | bfd_put_16 (abfd, contents, address); |
381 | 0 | break; |
382 | 0 | case 4: |
383 | 0 | if (howto->dst_mask != 0xffffffff) |
384 | | /* must be 32-bit instruction, always little-endian */ |
385 | 0 | bfd_putl32 (contents, address); |
386 | 0 | else |
387 | | /* must be 32-bit data (endianness dependent) */ |
388 | 0 | bfd_put_32 (abfd, contents, address); |
389 | 0 | break; |
390 | 0 | case 8: |
391 | 0 | bfd_put_64 (abfd, contents, address); |
392 | 0 | break; |
393 | 0 | default: |
394 | 0 | abort (); |
395 | 0 | } |
396 | | |
397 | 0 | return status; |
398 | 0 | } |
399 | | |
400 | | bfd_vma |
401 | | _bfd_aarch64_elf_resolve_relocation (bfd *input_bfd, |
402 | | bfd_reloc_code_real_type r_type, |
403 | | bfd_vma place, bfd_vma value, |
404 | | bfd_vma addend, bool weak_undef_p) |
405 | 0 | { |
406 | 0 | bool tls_reloc = true; |
407 | 0 | switch (r_type) |
408 | 0 | { |
409 | 0 | case BFD_RELOC_AARCH64_NONE: |
410 | 0 | case BFD_RELOC_AARCH64_TLSDESC_CALL: |
411 | 0 | break; |
412 | | |
413 | 0 | case BFD_RELOC_AARCH64_16_PCREL: |
414 | 0 | case BFD_RELOC_AARCH64_32_PCREL: |
415 | 0 | case BFD_RELOC_AARCH64_64_PCREL: |
416 | 0 | case BFD_RELOC_AARCH64_ADR_LO21_PCREL: |
417 | 0 | case BFD_RELOC_AARCH64_BRANCH19: |
418 | 0 | case BFD_RELOC_AARCH64_LD_LO19_PCREL: |
419 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G0: |
420 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G0_NC: |
421 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G1: |
422 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G1_NC: |
423 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G2: |
424 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G2_NC: |
425 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G3: |
426 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21: |
427 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19: |
428 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21: |
429 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19: |
430 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21: |
431 | 0 | case BFD_RELOC_AARCH64_TSTBR14: |
432 | 0 | if (weak_undef_p) |
433 | 0 | value = place; |
434 | 0 | value = value + addend - place; |
435 | 0 | break; |
436 | | |
437 | 0 | case BFD_RELOC_AARCH64_CALL26: |
438 | 0 | case BFD_RELOC_AARCH64_JUMP26: |
439 | 0 | value = value + addend - place; |
440 | 0 | break; |
441 | | |
442 | 0 | case BFD_RELOC_AARCH64_16: |
443 | 0 | case BFD_RELOC_AARCH64_32: |
444 | 0 | case BFD_RELOC_AARCH64_MOVW_G0: |
445 | 0 | case BFD_RELOC_AARCH64_MOVW_G0_NC: |
446 | 0 | case BFD_RELOC_AARCH64_MOVW_G0_S: |
447 | 0 | case BFD_RELOC_AARCH64_MOVW_G1: |
448 | 0 | case BFD_RELOC_AARCH64_MOVW_G1_NC: |
449 | 0 | case BFD_RELOC_AARCH64_MOVW_G1_S: |
450 | 0 | case BFD_RELOC_AARCH64_MOVW_G2: |
451 | 0 | case BFD_RELOC_AARCH64_MOVW_G2_NC: |
452 | 0 | case BFD_RELOC_AARCH64_MOVW_G2_S: |
453 | 0 | case BFD_RELOC_AARCH64_MOVW_G3: |
454 | 0 | tls_reloc = false; |
455 | | /* fall-through. */ |
456 | 0 | case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC: |
457 | 0 | case BFD_RELOC_AARCH64_TLSDESC_OFF_G1: |
458 | 0 | case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC: |
459 | 0 | case BFD_RELOC_AARCH64_TLSGD_MOVW_G1: |
460 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_HI12: |
461 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12: |
462 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: |
463 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12: |
464 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12: |
465 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12: |
466 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12: |
467 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0: |
468 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: |
469 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1: |
470 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC: |
471 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2: |
472 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12: |
473 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12: |
474 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12: |
475 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12: |
476 | | /* Weak Symbols and TLS relocations are implementation defined. For this |
477 | | case we choose to emit 0. */ |
478 | 0 | if (weak_undef_p && tls_reloc) |
479 | 0 | { |
480 | 0 | _bfd_error_handler (_("%pB: warning: Weak TLS is implementation " |
481 | 0 | "defined and may not work as expected"), |
482 | 0 | input_bfd); |
483 | 0 | value = place; |
484 | 0 | } |
485 | 0 | value = value + addend; |
486 | 0 | break; |
487 | | |
488 | 0 | case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL: |
489 | 0 | case BFD_RELOC_AARCH64_ADR_HI21_PCREL: |
490 | 0 | if (weak_undef_p) |
491 | 0 | value = PG (place); |
492 | 0 | value = PG (value + addend) - PG (place); |
493 | 0 | break; |
494 | | |
495 | 0 | case BFD_RELOC_AARCH64_GOT_LD_PREL19: |
496 | 0 | value = value + addend - place; |
497 | 0 | break; |
498 | | |
499 | 0 | case BFD_RELOC_AARCH64_ADR_GOT_PAGE: |
500 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21: |
501 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21: |
502 | 0 | case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: |
503 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21: |
504 | 0 | value = PG (value + addend) - PG (place); |
505 | 0 | break; |
506 | | |
507 | | /* Caller must make sure addend is the base address of .got section. */ |
508 | 0 | case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14: |
509 | 0 | case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15: |
510 | 0 | addend = PG (addend); |
511 | | /* Fall through. */ |
512 | 0 | case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15: |
513 | 0 | case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC: |
514 | 0 | case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1: |
515 | 0 | value = value - addend; |
516 | 0 | break; |
517 | | |
518 | 0 | case BFD_RELOC_AARCH64_ADD_LO12: |
519 | 0 | case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC: |
520 | 0 | case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC: |
521 | 0 | case BFD_RELOC_AARCH64_LDST128_LO12: |
522 | 0 | case BFD_RELOC_AARCH64_LDST16_LO12: |
523 | 0 | case BFD_RELOC_AARCH64_LDST32_LO12: |
524 | 0 | case BFD_RELOC_AARCH64_LDST64_LO12: |
525 | 0 | case BFD_RELOC_AARCH64_LDST8_LO12: |
526 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADD: |
527 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12: |
528 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC: |
529 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12: |
530 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LDR: |
531 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC: |
532 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC: |
533 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: |
534 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC: |
535 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC: |
536 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC: |
537 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC: |
538 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC: |
539 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: |
540 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: |
541 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: |
542 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: |
543 | 0 | value = PG_OFFSET (value + addend); |
544 | 0 | break; |
545 | | |
546 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12: |
547 | 0 | value = value + addend; |
548 | 0 | break; |
549 | | |
550 | 0 | case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1: |
551 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1: |
552 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC: |
553 | 0 | value = (value + addend) & (bfd_vma) 0xffff0000; |
554 | 0 | break; |
555 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12: |
556 | | /* Mask off low 12bits, keep all other high bits, so that the later |
557 | | generic code could check whehter there is overflow. */ |
558 | 0 | value = (value + addend) & ~(bfd_vma) 0xfff; |
559 | 0 | break; |
560 | | |
561 | 0 | case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC: |
562 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0: |
563 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC: |
564 | 0 | value = (value + addend) & (bfd_vma) 0xffff; |
565 | 0 | break; |
566 | | |
567 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2: |
568 | 0 | value = (value + addend) & ~(bfd_vma) 0xffffffff; |
569 | 0 | value -= place & ~(bfd_vma) 0xffffffff; |
570 | 0 | break; |
571 | | |
572 | 0 | default: |
573 | 0 | break; |
574 | 0 | } |
575 | | |
576 | 0 | return value; |
577 | 0 | } |
578 | | |
579 | | /* Support for core dump NOTE sections. */ |
580 | | |
581 | | bool |
582 | | _bfd_aarch64_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) |
583 | 1 | { |
584 | 1 | int offset; |
585 | 1 | size_t size; |
586 | | |
587 | 1 | switch (note->descsz) |
588 | 1 | { |
589 | 1 | default: |
590 | 1 | return false; |
591 | | |
592 | 0 | case 392: /* sizeof(struct elf_prstatus) on Linux/arm64. */ |
593 | | /* pr_cursig */ |
594 | 0 | elf_tdata (abfd)->core->signal |
595 | 0 | = bfd_get_16 (abfd, note->descdata + 12); |
596 | | |
597 | | /* pr_pid */ |
598 | 0 | elf_tdata (abfd)->core->lwpid |
599 | 0 | = bfd_get_32 (abfd, note->descdata + 32); |
600 | | |
601 | | /* pr_reg */ |
602 | 0 | offset = 112; |
603 | 0 | size = 272; |
604 | |
|
605 | 0 | break; |
606 | 1 | } |
607 | | |
608 | | /* Make a ".reg/999" section. */ |
609 | 0 | return _bfd_elfcore_make_pseudosection (abfd, ".reg", |
610 | 0 | size, note->descpos + offset); |
611 | 1 | } |
612 | | |
613 | | bool |
614 | | _bfd_aarch64_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) |
615 | 4 | { |
616 | 4 | switch (note->descsz) |
617 | 4 | { |
618 | 4 | default: |
619 | 4 | return false; |
620 | | |
621 | 0 | case 136: /* This is sizeof(struct elf_prpsinfo) on Linux/aarch64. */ |
622 | 0 | elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 24); |
623 | 0 | elf_tdata (abfd)->core->program |
624 | 0 | = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16); |
625 | 0 | elf_tdata (abfd)->core->command |
626 | 0 | = _bfd_elfcore_strndup (abfd, note->descdata + 56, 80); |
627 | 4 | } |
628 | | |
629 | | /* Note that for some reason, a spurious space is tacked |
630 | | onto the end of the args in some (at least one anyway) |
631 | | implementations, so strip it off if it exists. */ |
632 | | |
633 | 0 | { |
634 | 0 | char *command = elf_tdata (abfd)->core->command; |
635 | 0 | int n = strlen (command); |
636 | |
|
637 | 0 | if (0 < n && command[n - 1] == ' ') |
638 | 0 | command[n - 1] = '\0'; |
639 | 0 | } |
640 | |
|
641 | 0 | return true; |
642 | 4 | } |
643 | | |
644 | | char * |
645 | | _bfd_aarch64_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, |
646 | | ...) |
647 | 0 | { |
648 | 0 | switch (note_type) |
649 | 0 | { |
650 | 0 | default: |
651 | 0 | return NULL; |
652 | | |
653 | 0 | case NT_PRPSINFO: |
654 | 0 | { |
655 | 0 | char data[136] ATTRIBUTE_NONSTRING; |
656 | 0 | va_list ap; |
657 | |
|
658 | 0 | va_start (ap, note_type); |
659 | 0 | memset (data, 0, sizeof (data)); |
660 | 0 | strncpy (data + 40, va_arg (ap, const char *), 16); |
661 | | #if GCC_VERSION == 8000 || GCC_VERSION == 8001 |
662 | | DIAGNOSTIC_PUSH; |
663 | | /* GCC 8.0 and 8.1 warn about 80 equals destination size with |
664 | | -Wstringop-truncation: |
665 | | https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85643 |
666 | | */ |
667 | | DIAGNOSTIC_IGNORE_STRINGOP_TRUNCATION; |
668 | | #endif |
669 | 0 | strncpy (data + 56, va_arg (ap, const char *), 80); |
670 | | #if GCC_VERSION == 8000 || GCC_VERSION == 8001 |
671 | | DIAGNOSTIC_POP; |
672 | | #endif |
673 | 0 | va_end (ap); |
674 | |
|
675 | 0 | return elfcore_write_note (abfd, buf, bufsiz, "CORE", |
676 | 0 | note_type, data, sizeof (data)); |
677 | 0 | } |
678 | | |
679 | 0 | case NT_PRSTATUS: |
680 | 0 | { |
681 | 0 | char data[392]; |
682 | 0 | va_list ap; |
683 | 0 | long pid; |
684 | 0 | int cursig; |
685 | 0 | const void *greg; |
686 | |
|
687 | 0 | va_start (ap, note_type); |
688 | 0 | memset (data, 0, sizeof (data)); |
689 | 0 | pid = va_arg (ap, long); |
690 | 0 | bfd_put_32 (abfd, pid, data + 32); |
691 | 0 | cursig = va_arg (ap, int); |
692 | 0 | bfd_put_16 (abfd, cursig, data + 12); |
693 | 0 | greg = va_arg (ap, const void *); |
694 | 0 | memcpy (data + 112, greg, 272); |
695 | 0 | va_end (ap); |
696 | |
|
697 | 0 | return elfcore_write_note (abfd, buf, bufsiz, "CORE", |
698 | 0 | note_type, data, sizeof (data)); |
699 | 0 | } |
700 | 0 | } |
701 | 0 | } |
702 | | |
703 | | typedef struct |
704 | | { |
705 | | bfd *pbfd; |
706 | | asection* sec; |
707 | | } bfd_search_result_t; |
708 | | |
709 | | static inline bool |
710 | | bfd_is_non_dynamic_elf_object (bfd *abfd, elf_backend_data *out_be) |
711 | 0 | { |
712 | 0 | elf_backend_data *in_be = get_elf_backend_data (abfd); |
713 | |
|
714 | 0 | return bfd_get_flavour (abfd) == bfd_target_elf_flavour |
715 | 0 | && bfd_count_sections (abfd) != 0 |
716 | 0 | && (abfd->flags & (DYNAMIC | BFD_PLUGIN | BFD_LINKER_CREATED)) == 0 |
717 | 0 | && out_be->elf_machine_code == in_be->elf_machine_code |
718 | 0 | && out_be->s->elfclass == in_be->s->elfclass; |
719 | 0 | } |
720 | | |
721 | | /* Find the first input bfd with GNU properties. |
722 | | If such an input is found, set found to true and return the relevant input. |
723 | | Otherwise, return the last input of bfd inputs. */ |
724 | | static bfd_search_result_t |
725 | | bfd_linear_search_one_with_gnu_property (struct bfd_link_info *info) |
726 | 0 | { |
727 | 0 | elf_backend_data *be = get_elf_backend_data (info->output_bfd); |
728 | |
|
729 | 0 | bfd_search_result_t res = { |
730 | 0 | .pbfd = NULL, |
731 | 0 | .sec = NULL, |
732 | 0 | }; |
733 | |
|
734 | 0 | for (bfd *pbfd = info->input_bfds; pbfd != NULL; pbfd = pbfd->link.next) |
735 | 0 | if (bfd_is_non_dynamic_elf_object (pbfd, be)) |
736 | 0 | { |
737 | 0 | res.pbfd = pbfd; |
738 | | |
739 | | /* Does the input have a list of GNU properties ? */ |
740 | 0 | if (elf_properties (pbfd) != NULL) |
741 | 0 | break; |
742 | 0 | } |
743 | |
|
744 | 0 | if (res.pbfd != NULL) |
745 | 0 | res.sec = bfd_get_section_by_name (res.pbfd, NOTE_GNU_PROPERTY_SECTION_NAME); |
746 | |
|
747 | 0 | return res; |
748 | 0 | } |
749 | | |
750 | | /* Create a GNU property section for the given bfd input. */ |
751 | | static void |
752 | | _bfd_aarch64_elf_create_gnu_property_section (struct bfd_link_info *info, |
753 | | bfd *ebfd) |
754 | 0 | { |
755 | 0 | asection *sec; |
756 | 0 | sec = bfd_make_section_with_flags (ebfd, |
757 | 0 | NOTE_GNU_PROPERTY_SECTION_NAME, |
758 | 0 | (SEC_ALLOC |
759 | 0 | | SEC_LOAD |
760 | 0 | | SEC_IN_MEMORY |
761 | 0 | | SEC_READONLY |
762 | 0 | | SEC_HAS_CONTENTS |
763 | 0 | | SEC_DATA)); |
764 | 0 | unsigned align = (bfd_get_mach (ebfd) & bfd_mach_aarch64_ilp32) ? 2 : 3; |
765 | 0 | if (sec == NULL |
766 | 0 | || !bfd_set_section_alignment (sec, align)) |
767 | 0 | info->callbacks->fatal (_("%P: failed to create %s\n"), |
768 | 0 | NOTE_GNU_PROPERTY_SECTION_NAME); |
769 | | |
770 | 0 | elf_section_type (sec) = SHT_NOTE; |
771 | 0 | } |
772 | | |
773 | | static const int GNU_PROPERTY_ISSUES_MAX = 20; |
774 | | |
775 | | /* Report a summary of the issues met during the merge of the GNU properties, if |
776 | | the number of issues goes above GNU_PROPERTY_ISSUES_MAX. */ |
777 | | static void |
778 | | _bfd_aarch64_report_summary_merge_issues (struct bfd_link_info *info) |
779 | 0 | { |
780 | 0 | const struct elf_aarch64_obj_tdata * tdata |
781 | 0 | = elf_aarch64_tdata (info->output_bfd); |
782 | |
|
783 | 0 | if (tdata->n_bti_issues > GNU_PROPERTY_ISSUES_MAX |
784 | 0 | && tdata->sw_protections.bti_report != MARKING_NONE) |
785 | 0 | { |
786 | 0 | const char *msg |
787 | 0 | = (tdata->sw_protections.bti_report == MARKING_ERROR) |
788 | 0 | ? _("%Xerror: found a total of %d inputs incompatible with " |
789 | 0 | "BTI requirements.\n") |
790 | 0 | : _("warning: found a total of %d inputs incompatible with " |
791 | 0 | "BTI requirements.\n"); |
792 | 0 | info->callbacks->einfo (msg, tdata->n_bti_issues); |
793 | 0 | } |
794 | |
|
795 | 0 | if (tdata->n_gcs_issues > GNU_PROPERTY_ISSUES_MAX |
796 | 0 | && tdata->sw_protections.gcs_report != MARKING_NONE) |
797 | 0 | { |
798 | 0 | const char *msg |
799 | 0 | = (tdata->sw_protections.gcs_report == MARKING_ERROR) |
800 | 0 | ? _("%Xerror: found a total of %d inputs incompatible with " |
801 | 0 | "GCS requirements.\n") |
802 | 0 | : _("warning: found a total of %d inputs incompatible with " |
803 | 0 | "GCS requirements.\n"); |
804 | 0 | info->callbacks->einfo (msg, tdata->n_gcs_issues); |
805 | 0 | } |
806 | |
|
807 | 0 | if (tdata->n_gcs_dynamic_issues > GNU_PROPERTY_ISSUES_MAX |
808 | 0 | && tdata->sw_protections.gcs_report_dynamic != MARKING_NONE) |
809 | 0 | { |
810 | 0 | const char *msg |
811 | 0 | = (tdata->sw_protections.gcs_report_dynamic == MARKING_ERROR) |
812 | 0 | ? _("%Xerror: found a total of %d dynamically-linked objects " |
813 | 0 | "incompatible with GCS requirements.\n") |
814 | 0 | : _("warning: found a total of %d dynamically-linked objects " |
815 | 0 | "incompatible with GCS requirements.\n"); |
816 | 0 | info->callbacks->einfo (msg, tdata->n_gcs_dynamic_issues); |
817 | 0 | } |
818 | 0 | } |
819 | | |
820 | | /* Perform a look-up of a property in an unsorted list of properties. This is |
821 | | useful when the list of properties of an object has not been sorted yet. */ |
822 | | static uint32_t |
823 | | _bfd_aarch64_prop_linear_lookup (elf_property_list *properties, |
824 | | unsigned int pr_type) |
825 | 0 | { |
826 | 0 | for (elf_property_list *p = properties; p != NULL; p = p->next) |
827 | 0 | if (p->property.pr_type == pr_type) |
828 | 0 | return p->property.u.number; |
829 | 0 | return 0; |
830 | 0 | } |
831 | | |
832 | | /* Compare the GNU properties of the current dynamic object, with the ones of |
833 | | the output BFD. Today, we only care about GCS feature stored in |
834 | | GNU_PROPERTY_AARCH64_FEATURE_1. */ |
835 | | static void |
836 | | _bfd_aarch64_compare_dynamic_obj_prop_against_outprop( |
837 | | struct bfd_link_info *info, |
838 | | const uint32_t outprop, |
839 | | bfd *pbfd) |
840 | 0 | { |
841 | 0 | if (!(outprop & GNU_PROPERTY_AARCH64_FEATURE_1_GCS)) |
842 | 0 | return; |
843 | | |
844 | 0 | const uint32_t dyn_obj_aarch64_feature_prop = |
845 | 0 | _bfd_aarch64_prop_linear_lookup (elf_properties (pbfd), |
846 | 0 | GNU_PROPERTY_AARCH64_FEATURE_1_AND); |
847 | 0 | if (!(dyn_obj_aarch64_feature_prop & GNU_PROPERTY_AARCH64_FEATURE_1_GCS)) |
848 | 0 | _bfd_aarch64_elf_check_gcs_report (info, pbfd); |
849 | 0 | } |
850 | | |
851 | | /* Check compatibility between the GNU properties of the ouput BFD and the |
852 | | linked dynamic objects. */ |
853 | | static void |
854 | | _bfd_aarch64_elf_check_gnu_properties_linked_dynamic_objects ( |
855 | | struct bfd_link_info * info, |
856 | | const uint32_t outprop) |
857 | 0 | { |
858 | 0 | elf_backend_data *bed = get_elf_backend_data (info->output_bfd); |
859 | 0 | const int elf_machine_code = bed->elf_machine_code; |
860 | 0 | const unsigned int elfclass = bed->s->elfclass; |
861 | |
|
862 | 0 | for (bfd *pbfd = info->input_bfds; pbfd != NULL; pbfd = pbfd->link.next) |
863 | | /* Ignore GNU properties from non-ELF objects or ELF objects with different |
864 | | machine code. */ |
865 | 0 | if ((pbfd->flags & DYNAMIC) != 0 |
866 | 0 | && (bfd_get_flavour (pbfd) == bfd_target_elf_flavour) |
867 | 0 | && (get_elf_backend_data (pbfd)->elf_machine_code == elf_machine_code) |
868 | 0 | && (get_elf_backend_data (pbfd)->s->elfclass == elfclass)) |
869 | 0 | _bfd_aarch64_compare_dynamic_obj_prop_against_outprop(info, outprop, |
870 | 0 | pbfd); |
871 | 0 | } |
872 | | |
873 | | /* Decode the encoded version number corresponding to the Object Attribute |
874 | | version. Return the version on success, UNSUPPORTED on failure. */ |
875 | | obj_attr_version_t |
876 | | _bfd_aarch64_obj_attrs_version_dec (uint8_t encoded_version) |
877 | 328 | { |
878 | 328 | if (encoded_version == 'A') |
879 | 302 | return OBJ_ATTR_V2; |
880 | 26 | return OBJ_ATTR_VERSION_UNSUPPORTED; |
881 | 328 | } |
882 | | |
883 | | /* Encode the Object Attribute version into a byte. */ |
884 | | uint8_t |
885 | | _bfd_aarch64_obj_attrs_version_enc (obj_attr_version_t version) |
886 | 0 | { |
887 | 0 | if (version == OBJ_ATTR_V2) |
888 | 0 | return 'A'; |
889 | 0 | abort (); |
890 | 0 | } |
891 | | |
892 | | /* List of known attributes in the subsection "aeabi_feature_and_bits". |
893 | | Note: the array below has to be sorted by the tag's integer value that can |
894 | | be found in the document "Build Attributes for the Arm® 64-bit Architecture |
895 | | (AArch64)". */ |
896 | | static const obj_attr_info_t known_attrs_aeabi_feature_and_bits[] = |
897 | | { |
898 | | { .tag = {"Tag_Feature_BTI", Tag_Feature_BTI} }, |
899 | | { .tag = {"Tag_Feature_PAC", Tag_Feature_PAC} }, |
900 | | { .tag = {"Tag_Feature_GCS", Tag_Feature_GCS} }, |
901 | | }; |
902 | | |
903 | | /* List of known attributes in the subsection "aeabi_pauthabi". |
904 | | Notes: |
905 | | - "aeabi_pauthabi" is a required subsection to use PAuthABI (which is |
906 | | today only supported by LLVM, unsupported by GCC 15 and lower. There is no |
907 | | plan to add support for it in the future). A value of 0 for any the tags |
908 | | below means that the user did not permit this entity to use the PAuthABI. |
909 | | - the array below has to be sorted by the tag's integer value that can be |
910 | | found in the document "Build Attributes for the Arm® 64-bit Architecture |
911 | | (AArch64)". */ |
912 | | static const obj_attr_info_t known_attrs_aeabi_pauthabi[] = |
913 | | { |
914 | | { .tag = {"Tag_PAuth_Platform", Tag_PAuth_Platform} }, |
915 | | { .tag = {"Tag_PAuth_Schema", Tag_PAuth_Schema} }, |
916 | | }; |
917 | | |
918 | | /* List of known subsections. |
919 | | Note: this array is exported by the backend, and has to be sorted using |
920 | | the same criteria as in _bfd_elf_obj_attr_subsection_v2_cmp(). */ |
921 | | const known_subsection_v2_t aarch64_obj_attr_v2_known_subsections[2] = |
922 | | { |
923 | | { |
924 | | .subsec_name = "aeabi_feature_and_bits", |
925 | | .known_attrs = known_attrs_aeabi_feature_and_bits, |
926 | | .optional = true, |
927 | | .encoding = OA_ENC_ULEB128, |
928 | | .len = ARRAY_SIZE (known_attrs_aeabi_feature_and_bits), |
929 | | }, |
930 | | { |
931 | | .subsec_name = "aeabi_pauthabi", |
932 | | .known_attrs = known_attrs_aeabi_pauthabi, |
933 | | .optional = false, |
934 | | .encoding = OA_ENC_ULEB128, |
935 | | .len = ARRAY_SIZE (known_attrs_aeabi_pauthabi), |
936 | | }, |
937 | | }; |
938 | | |
939 | | /* Record the pair (TAG, VALUE) into SUBSEC. */ |
940 | | void |
941 | | _bfd_aarch64_oav2_record (obj_attr_subsection_v2_t *subsec, |
942 | | Tag_Feature_Set feature_tag, |
943 | | uint32_t value) |
944 | 0 | { |
945 | 0 | union obj_attr_value_v2 data; |
946 | 0 | data.uint = value; |
947 | 0 | obj_attr_v2_t *attr = bfd_elf_obj_attr_v2_init (feature_tag, data); |
948 | 0 | LINKED_LIST_APPEND (obj_attr_v2_t) (subsec, attr); |
949 | 0 | } |
950 | | |
951 | | /* Wrapper around the recording of the pair (TAG, VALUE) into SUBSEC called from |
952 | | a context of translation from GNU properties. */ |
953 | | static void |
954 | | obj_attr_v2_record_tag_value (obj_attr_subsection_v2_t *subsec, |
955 | | Tag_Feature_Set tag, |
956 | | bool value) |
957 | 0 | { |
958 | 0 | obj_attr_v2_t *attr; |
959 | 0 | attr = bfd_obj_attr_v2_find_by_tag (subsec, tag, false); |
960 | 0 | if (attr != NULL) |
961 | 0 | { |
962 | 0 | if (attr->val.uint != value) |
963 | 0 | { |
964 | | /* If we find an existing value for the given object attributes and |
965 | | this value is different from the new one, it can mean two things: |
966 | | - either the values are conflicting, and we need to raise an |
967 | | error. |
968 | | - either there are several GNU properties AARCH64_FEATURE_1_AND |
969 | | which were recorded, but its final value is the result of the |
970 | | merge of those separate values. |
971 | | For now, only the second case occurs. */ |
972 | 0 | uint32_t merged_val = attr->val.uint | value; |
973 | 0 | _bfd_aarch64_oav2_record (subsec, tag, merged_val); |
974 | 0 | } |
975 | | /* else: nothing to do. */ |
976 | 0 | } |
977 | 0 | else |
978 | 0 | _bfd_aarch64_oav2_record (subsec, tag, value); |
979 | 0 | } |
980 | | |
981 | | /* Translate the relevant GNU properties in P to their Object Attributes v2 |
982 | | equivalents. */ |
983 | | void |
984 | | _bfd_aarch64_translate_gnu_props_to_obj_attrs |
985 | | (const bfd *abfd, const elf_property_list *p) |
986 | 0 | { |
987 | 0 | if (p->property.pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) |
988 | 0 | { |
989 | 0 | const elf_property *prop = &p->property; |
990 | 0 | BFD_ASSERT (prop->pr_kind == property_number); |
991 | |
|
992 | 0 | obj_attr_subsection_v2_t *subsec = bfd_obj_attr_subsection_v2_find_by_name |
993 | 0 | (elf_obj_attr_subsections (abfd).first, "aeabi_feature_and_bits", false); |
994 | |
|
995 | 0 | bool new_subsec = false; |
996 | 0 | if (subsec == NULL) |
997 | 0 | { |
998 | 0 | subsec = bfd_elf_obj_attr_subsection_v2_init |
999 | 0 | (xstrdup ("aeabi_feature_and_bits"), OA_SUBSEC_PUBLIC, true, |
1000 | 0 | OA_ENC_ULEB128); |
1001 | 0 | new_subsec = true; |
1002 | 0 | } |
1003 | |
|
1004 | 0 | bool bti_bit = prop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI; |
1005 | 0 | bool pac_bit = prop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_PAC; |
1006 | 0 | bool gcs_bit = prop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_GCS; |
1007 | |
|
1008 | 0 | obj_attr_v2_record_tag_value (subsec, Tag_Feature_BTI, bti_bit); |
1009 | 0 | obj_attr_v2_record_tag_value (subsec, Tag_Feature_PAC, pac_bit); |
1010 | 0 | obj_attr_v2_record_tag_value (subsec, Tag_Feature_GCS, gcs_bit); |
1011 | |
|
1012 | 0 | if (new_subsec) |
1013 | 0 | LINKED_LIST_APPEND (obj_attr_subsection_v2_t) |
1014 | 0 | (&elf_obj_attr_subsections (abfd), subsec); |
1015 | 0 | } |
1016 | 0 | } |
1017 | | |
1018 | | /* Translate relevant Object Attributes v2 in SUBSEC to GNU properties. */ |
1019 | | void |
1020 | | _bfd_aarch64_translate_obj_attrs_to_gnu_props |
1021 | | (bfd *abfd, const obj_attr_subsection_v2_t *subsec) |
1022 | 0 | { |
1023 | | /* Note: there is no need to create the GNU properties section here. It will |
1024 | | be handled later by setup_gnu_properties. */ |
1025 | |
|
1026 | 0 | if (strcmp (subsec->name, "aeabi_feature_and_bits") == 0) |
1027 | 0 | { |
1028 | 0 | uint32_t gnu_property_aarch64_features = 0; |
1029 | |
|
1030 | 0 | for (const obj_attr_v2_t *attr = subsec->first; |
1031 | 0 | attr != NULL; |
1032 | 0 | attr = attr->next) |
1033 | 0 | { |
1034 | 0 | if (attr->tag == Tag_Feature_BTI && attr->val.uint == 1) |
1035 | 0 | gnu_property_aarch64_features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI; |
1036 | 0 | else if (attr->tag == Tag_Feature_PAC && attr->val.uint == 1) |
1037 | 0 | gnu_property_aarch64_features |= GNU_PROPERTY_AARCH64_FEATURE_1_PAC; |
1038 | 0 | else if (attr->tag == Tag_Feature_GCS && attr->val.uint == 1) |
1039 | 0 | gnu_property_aarch64_features |= GNU_PROPERTY_AARCH64_FEATURE_1_GCS; |
1040 | 0 | } |
1041 | | |
1042 | | /* Note: _bfd_elf_get_property find the existing property, or create one. |
1043 | | The insertion is already done by it. */ |
1044 | 0 | elf_property *prop |
1045 | 0 | = _bfd_elf_get_property (abfd, GNU_PROPERTY_AARCH64_FEATURE_1_AND, 4); |
1046 | 0 | prop->u.number |= gnu_property_aarch64_features; |
1047 | 0 | prop->pr_kind = property_number; |
1048 | 0 | } |
1049 | 0 | } |
1050 | | |
1051 | | /* Check whether the given ATTR is managed by the backend, and if that is the |
1052 | | case, initialize ATTR with its default value coming from the known tag |
1053 | | registry. |
1054 | | True if the default value for the tag is managed by the backend, and was |
1055 | | initialized. False otherwise. */ |
1056 | | bool |
1057 | | _bfd_aarch64_oav2_default_value |
1058 | | (const struct bfd_link_info *info ATTRIBUTE_UNUSED, |
1059 | | const obj_attr_info_t *tag_info ATTRIBUTE_UNUSED, |
1060 | | const obj_attr_subsection_v2_t *subsec ATTRIBUTE_UNUSED, |
1061 | | obj_attr_v2_t *attr ATTRIBUTE_UNUSED) |
1062 | 0 | { |
1063 | | /* For now, there is no default value set by the backend. The default BTI and |
1064 | | GCS values are set by the respective command-line options '-z force-bti' |
1065 | | and '-z gcs'. */ |
1066 | |
|
1067 | 0 | return false; |
1068 | 0 | } |
1069 | | |
1070 | | /* Merge the values from LHS, RHS, FROZEN, and return the merge result. LHS, |
1071 | | RHS and FROZEN correspond to an attribute from SUBSEC with the same tag, but |
1072 | | from three different contexts: |
1073 | | - LHS corresponds to the global merge result. |
1074 | | - RHS corresponds to the new value that is merged into the global merge |
1075 | | result. |
1076 | | - FROZEN corresponds to the value coming from some configuration context |
1077 | | (usually a command-line option) and which is immutable for the whole |
1078 | | merge process. */ |
1079 | | obj_attr_v2_merge_result_t |
1080 | | _bfd_aarch64_oav2_attr_merge (const struct bfd_link_info *info, |
1081 | | const bfd *abfd, |
1082 | | const obj_attr_subsection_v2_t *subsec, |
1083 | | const obj_attr_v2_t *lhs, const obj_attr_v2_t *rhs, |
1084 | | const obj_attr_v2_t *frozen) |
1085 | 0 | { |
1086 | 0 | obj_attr_v2_merge_result_t res = { |
1087 | 0 | .merge = false, |
1088 | 0 | .val.uint = 0, |
1089 | 0 | .reason = OAv2_MERGE_OK, |
1090 | 0 | }; |
1091 | | |
1092 | | /* No need to list required sections here, they are handled separately as |
1093 | | they require a perfect one-to-one match for all the tag values. */ |
1094 | 0 | if (strcmp (subsec->name, "aeabi_feature_and_bits") == 0) |
1095 | 0 | { |
1096 | 0 | BFD_ASSERT (subsec->encoding == OA_ENC_ULEB128 && subsec->optional); |
1097 | 0 | const obj_attr_info_t *attr_info |
1098 | 0 | = _bfd_obj_attr_v2_find_known_by_tag (get_elf_backend_data (abfd), |
1099 | 0 | subsec->name, lhs->tag); |
1100 | 0 | if (attr_info == NULL) |
1101 | 0 | { |
1102 | 0 | info->callbacks->einfo |
1103 | 0 | (_("%pB: warning: cannot merge unknown tag 'Tag_unknown_%" PRIu64 "'" |
1104 | 0 | " (=0x%" PRIx32 ") in subsection '%s'\n"), |
1105 | 0 | abfd, rhs->tag, rhs->val.uint, subsec->name); |
1106 | 0 | res.reason = OAv2_MERGE_UNSUPPORTED; |
1107 | 0 | return res; |
1108 | 0 | } |
1109 | | |
1110 | | /* For now, there is no different between the tags of this section, all |
1111 | | will be merged in the same way. */ |
1112 | 0 | res = _bfd_obj_attr_v2_merge_AND (info, abfd, subsec, lhs, rhs, frozen); |
1113 | |
|
1114 | 0 | const aarch64_protection_opts *sw_protections |
1115 | 0 | = &elf_aarch64_tdata (info->output_bfd)->sw_protections; |
1116 | 0 | aarch64_feature_marking_report bti_report = sw_protections->bti_report; |
1117 | 0 | aarch64_feature_marking_report gcs_report = sw_protections->gcs_report; |
1118 | |
|
1119 | 0 | if (rhs->tag == Tag_Feature_BTI |
1120 | 0 | && bti_report != MARKING_NONE |
1121 | 0 | && (sw_protections->plt_type & PLT_BTI) |
1122 | 0 | && rhs->val.uint == 0) |
1123 | 0 | _bfd_aarch64_elf_check_bti_report (info, abfd); |
1124 | |
|
1125 | 0 | if ((rhs->tag == Tag_Feature_GCS) && (gcs_report != MARKING_NONE) |
1126 | 0 | && (sw_protections->gcs_type == GCS_ALWAYS) && (rhs->val.uint == 0)) |
1127 | 0 | _bfd_aarch64_elf_check_gcs_report (info, abfd); |
1128 | | |
1129 | | /* Make sure that frozen bits don't disappear from REF when it will be |
1130 | | compared to the next file. */ |
1131 | 0 | if (frozen != NULL) |
1132 | 0 | res.val.uint |= frozen->val.uint; |
1133 | 0 | } |
1134 | 0 | else |
1135 | 0 | res.reason = OAv2_MERGE_UNSUPPORTED; |
1136 | | |
1137 | 0 | return res; |
1138 | 0 | } |
1139 | | |
1140 | | /* Check for incompatibilities with PAuthABI attributes. */ |
1141 | | static bool |
1142 | | aarch64_check_pauthabi_attributes (const struct bfd_link_info *info) |
1143 | 0 | { |
1144 | | /* The subsection "aeabi_pauthabi" contains information about the Pointer |
1145 | | Authentication Signing schema when the object uses an extension to ELF, |
1146 | | PAUTHABI64, which is today only supported by LLVM, and not supported by |
1147 | | GCC 15 toolchain or ealier ones. There is no plan to add support for it |
1148 | | in the future. The pointers that are signed as well as the modifiers and |
1149 | | key used for each type of pointer are known as the signing schema. |
1150 | | The AEABI Build attributes specification defines the following tuple values |
1151 | | of (Tag_Pauth_Platform, Tag_Pauth_Schema): |
1152 | | - The tuple (0, 0) is obtained when both attributes are explicitly set to |
1153 | | 0 or are implicitly set to 0 due to the rules for setting default values |
1154 | | for public tags. This represents an ELF file which makes no use of the |
1155 | | PAuthABI extension. |
1156 | | - The tuple (0, 1) is reserved for the "Invalid" platform. ELF files with |
1157 | | an "Invalid" platform are incompatible with the PAuth ABI Extension. |
1158 | | - The tuples (0, N) where N > 1 are reserved. |
1159 | | - The tuples (M, N) where M is the id of one of the registered platforms |
1160 | | defined in PAuthABI64, represents a valid signing schema. (M, 0) |
1161 | | represents a schema version of 0 for platform M. |
1162 | | Given that the GNU linker does not support PAuthABI, it cannot do anything |
1163 | | with values others than (0, 0) or (0, 1). |
1164 | | The check below enforces either that the output object has either no |
1165 | | subsection "aeabi_pauthabi", or the tuple is set to (0, 0) and (0, 1). */ |
1166 | |
|
1167 | 0 | obj_attr_subsection_v2_t *subsecs |
1168 | 0 | = elf_obj_attr_subsections (info->output_bfd).first; |
1169 | 0 | const obj_attr_subsection_v2_t *subsec |
1170 | 0 | = bfd_obj_attr_subsection_v2_find_by_name (subsecs, "aeabi_pauthabi", true); |
1171 | 0 | if (subsec == NULL) |
1172 | 0 | return true; |
1173 | | |
1174 | 0 | int platform_id = 0; |
1175 | 0 | int version_id = 0; |
1176 | |
|
1177 | 0 | const obj_attr_v2_t *attr |
1178 | 0 | = bfd_obj_attr_v2_find_by_tag (subsec, Tag_PAuth_Platform, true); |
1179 | 0 | if (attr != NULL) |
1180 | 0 | platform_id = attr->val.uint; |
1181 | |
|
1182 | 0 | attr = bfd_obj_attr_v2_find_by_tag (subsec, Tag_PAuth_Schema, true); |
1183 | 0 | if (attr != NULL) |
1184 | 0 | version_id = attr->val.uint; |
1185 | |
|
1186 | 0 | if (! ((platform_id == 0 && version_id == 0) |
1187 | 0 | || (platform_id == 0 && version_id == 1))) |
1188 | 0 | { |
1189 | 0 | info->callbacks->einfo |
1190 | 0 | (_("%Xerror: the GNU linker does not support PAuthABI. Any value " |
1191 | 0 | "different from (platform = 0, schema = 0) or (platform = 0, schema " |
1192 | 0 | "= 1) is not supported.\n")); |
1193 | 0 | return false; |
1194 | 0 | } |
1195 | | |
1196 | 0 | return true; |
1197 | 0 | } |
1198 | | |
1199 | | /* Merge the AEABI Build Attributes present in the input BFDs, raise any |
1200 | | compatibility issue, and write the merge result to OBFD. |
1201 | | |
1202 | | AArch64 backend declares two vendor subsections, and their associated tags: |
1203 | | - aeabi_feature_and_bits: contains tags that describe the same optional |
1204 | | bits as the GNU_PROPERTY_AARCH64_FEATURE_1_AND. For now, the following |
1205 | | attributes are recognized: |
1206 | | - Tag_Feature_BTI: means that all the executable sections are |
1207 | | compatible with Branch Target Identification (BTI) mechanism. |
1208 | | - Tag_Feature_PAC: means that all the executable sections have been |
1209 | | protected with Return Address Signing. |
1210 | | - Tag_Feature_GCS: means that all the executable sections are |
1211 | | compatible with the Guarded Control Stack (GCS) extension. |
1212 | | - aeabi_pauthabi: contains information about the Pointer Authentication |
1213 | | Signing schema when the object uses an extension to ELF, PAUTHABI64, |
1214 | | which is currently not supported by GCC toolchain. The pointers that |
1215 | | are signed as well as the modifiers and key used for each type of pointer |
1216 | | are known as the signing schema. The support of this subsection is there |
1217 | | for completeness with the AEABI Build Attributes document, and allows |
1218 | | readelf to dump the data nicely, and the linker to detect a use of a |
1219 | | signing schema, and error. |
1220 | | - Tag_PAuth_Paltform: the platform vendor id. |
1221 | | - Tag_PAuth_Schema: the version numner of the schema. |
1222 | | |
1223 | | For backward-compatibilty purpose, AArch64 backend translates |
1224 | | GNU_PROPERTY_AARCH64_FEATURE_1_AND in input files to its OAv2 equivalents. |
1225 | | The frozen set of OAv2 is populated with values derived from command-line |
1226 | | options for BTI (-z force-bti) and GCS (-z gcs=*). |
1227 | | It also reports incompatibilities for BTI and GCS, and set BTI PLT type |
1228 | | depending on the OAv2 merge result. |
1229 | | Regarding incompatibilities, only the ones detected in objects constituting |
1230 | | the output link unit will be reported. Supports for detecting incompatibi- |
1231 | | -lities in shared objects might be a future work to bring it in pair with |
1232 | | thenGNU properties merge. However, since OAv2 are translated to GNU |
1233 | | properties, detection will still happen so this feature seems redundant and |
1234 | | of little value given the backward compatibility support for GNU properties |
1235 | | is required (see next paragraph). |
1236 | | Finally, it translates OAv2s in subsection "aeabi_feature_and_bits" to |
1237 | | GNU_PROPERTY_AARCH64_FEATURE_1_AND as GNU properties are required for |
1238 | | the dynamic linker (it does not understand OAv2s yet). */ |
1239 | | bfd * |
1240 | | _bfd_aarch64_elf_link_setup_object_attributes (struct bfd_link_info *info) |
1241 | 0 | { |
1242 | 0 | bfd *pbfd = _bfd_elf_link_setup_object_attributes (info); |
1243 | | |
1244 | | /* Check PAuthABI compatibility. */ |
1245 | 0 | if (! aarch64_check_pauthabi_attributes (info)) |
1246 | 0 | return NULL; |
1247 | | |
1248 | | /* Set the flag marking whether the merge of object attributes was done so |
1249 | | that setup_gnu_properties does not raise the same errors/warning again. */ |
1250 | 0 | elf_aarch64_tdata (info->output_bfd)->oa_merge_done = true; |
1251 | |
|
1252 | 0 | return pbfd; |
1253 | 0 | } |
1254 | | |
1255 | | /* Find the first input bfd with GNU property and merge it with GPROP. If no |
1256 | | such input is found, add it to a new section at the last input. Update |
1257 | | GPROP accordingly. */ |
1258 | | bfd * |
1259 | | _bfd_aarch64_elf_link_setup_gnu_properties (struct bfd_link_info *info) |
1260 | 0 | { |
1261 | 0 | struct elf_aarch64_obj_tdata *tdata = elf_aarch64_tdata (info->output_bfd); |
1262 | 0 | uint32_t outprop = tdata->gnu_property_aarch64_feature_1_and; |
1263 | |
|
1264 | 0 | bfd_search_result_t res = bfd_linear_search_one_with_gnu_property (info); |
1265 | | |
1266 | | /* If ebfd != NULL it is either an input with property note or the last input. |
1267 | | Either way if we have an output GNU property that was provided, we should |
1268 | | add it (by creating a section if needed). */ |
1269 | 0 | if (res.pbfd != NULL) |
1270 | 0 | { |
1271 | | /* If no GNU property note section was found, create one. |
1272 | | |
1273 | | Note: If there is no .gnu.note.property section, we might think that |
1274 | | elf_properties (res.pbfd) is always NULL. However, this is not always |
1275 | | true for the following reasons: |
1276 | | - PR23900: old linkers were treating .note.gnu.property as a generic |
1277 | | note section, so old objects might contain properties inside .note |
1278 | | instead of .note.gnu.property. In this case, the section won't be |
1279 | | detected but the properties are still parsed. Consequently, |
1280 | | elf_properties (res.pbfd) is populated and different from NULL (see |
1281 | | https://sourceware.org/bugzilla/show_bug.cgi?id=23900 for more |
1282 | | details). |
1283 | | - since the introduction of the object attributes, once the merge |
1284 | | of the OAs is done, some of the OAs can be translated to GNU |
1285 | | properties like GNU_PROPERTY_AARCH64_FEATURE_1_AND. In this case, |
1286 | | we need to check explicitly for the presence of the GNU properties |
1287 | | that might be added by the BAs merge. */ |
1288 | 0 | if (res.sec == NULL |
1289 | 0 | && (elf_properties (res.pbfd) == NULL |
1290 | 0 | || _bfd_elf_find_property (elf_properties (res.pbfd), |
1291 | 0 | GNU_PROPERTY_AARCH64_FEATURE_1_AND, |
1292 | 0 | NULL))) |
1293 | 0 | _bfd_aarch64_elf_create_gnu_property_section (info, res.pbfd); |
1294 | | |
1295 | | /* Merge the found input property with output properties. Note: if no |
1296 | | property was found, _bfd_elf_get_property will create one. */ |
1297 | 0 | elf_property *prop |
1298 | 0 | = _bfd_elf_get_property (res.pbfd, |
1299 | 0 | GNU_PROPERTY_AARCH64_FEATURE_1_AND, |
1300 | 0 | 4); |
1301 | | |
1302 | | /* Check for a feature mismatch and report issue (if any) before this |
1303 | | information get lost as the value of ebfd will be overriden with |
1304 | | outprop. */ |
1305 | 0 | if ((outprop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) |
1306 | 0 | && !(prop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) |
1307 | 0 | _bfd_aarch64_elf_check_bti_report (info, res.pbfd); |
1308 | |
|
1309 | 0 | if (tdata->sw_protections.gcs_type == GCS_NEVER) |
1310 | 0 | prop->u.number &= ~GNU_PROPERTY_AARCH64_FEATURE_1_GCS; |
1311 | 0 | else if ((outprop & GNU_PROPERTY_AARCH64_FEATURE_1_GCS) |
1312 | 0 | && !(prop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_GCS)) |
1313 | 0 | _bfd_aarch64_elf_check_gcs_report (info, res.pbfd); |
1314 | |
|
1315 | 0 | prop->u.number |= outprop; |
1316 | 0 | if (prop->u.number == 0) |
1317 | 0 | prop->pr_kind = property_remove; |
1318 | 0 | else |
1319 | 0 | prop->pr_kind = property_number; |
1320 | 0 | } |
1321 | | |
1322 | | /* Set up generic GNU properties, and merge them with the backend-specific |
1323 | | ones (if any). pbfd points to the first relocatable ELF input with |
1324 | | GNU properties (if found). */ |
1325 | 0 | bfd *pbfd = _bfd_elf_link_setup_gnu_properties (info); |
1326 | |
|
1327 | 0 | if (pbfd != NULL) |
1328 | 0 | { |
1329 | 0 | elf_property_list *p; |
1330 | 0 | elf_property_list *plist = elf_properties (pbfd); |
1331 | | |
1332 | | /* If pbfd has any GNU_PROPERTY_AARCH64_FEATURE_1_AND properties, update |
1333 | | outprop accordingly. */ |
1334 | 0 | if ((p = _bfd_elf_find_property (plist, |
1335 | 0 | GNU_PROPERTY_AARCH64_FEATURE_1_AND, NULL)) |
1336 | 0 | != NULL) |
1337 | 0 | outprop = p->property.u.number |
1338 | 0 | & (GNU_PROPERTY_AARCH64_FEATURE_1_BTI |
1339 | 0 | | GNU_PROPERTY_AARCH64_FEATURE_1_PAC |
1340 | 0 | | GNU_PROPERTY_AARCH64_FEATURE_1_GCS); |
1341 | 0 | } |
1342 | |
|
1343 | 0 | tdata->gnu_property_aarch64_feature_1_and = outprop; |
1344 | |
|
1345 | 0 | _bfd_aarch64_elf_check_gnu_properties_linked_dynamic_objects (info, outprop); |
1346 | |
|
1347 | 0 | _bfd_aarch64_report_summary_merge_issues (info); |
1348 | |
|
1349 | 0 | return pbfd; |
1350 | 0 | } |
1351 | | |
1352 | | /* Define elf_backend_parse_gnu_properties for AArch64. */ |
1353 | | enum elf_property_kind |
1354 | | _bfd_aarch64_elf_parse_gnu_properties (bfd *abfd, unsigned int type, |
1355 | | bfd_byte *ptr, unsigned int datasz) |
1356 | 0 | { |
1357 | 0 | elf_property *prop; |
1358 | |
|
1359 | 0 | switch (type) |
1360 | 0 | { |
1361 | 0 | case GNU_PROPERTY_AARCH64_FEATURE_1_AND: |
1362 | 0 | if (datasz != 4) |
1363 | 0 | { |
1364 | 0 | _bfd_error_handler |
1365 | 0 | ( _("error: %pB: <corrupt AArch64 used size: 0x%x>"), |
1366 | 0 | abfd, datasz); |
1367 | 0 | return property_corrupt; |
1368 | 0 | } |
1369 | 0 | prop = _bfd_elf_get_property (abfd, type, datasz); |
1370 | | /* Merge AArch64 feature properties together if they are declared in |
1371 | | different AARCH64_FEATURE_1_AND properties. */ |
1372 | 0 | prop->u.number |= bfd_h_get_32 (abfd, ptr); |
1373 | 0 | prop->pr_kind = property_number; |
1374 | 0 | break; |
1375 | | |
1376 | 0 | default: |
1377 | 0 | return property_ignored; |
1378 | 0 | } |
1379 | | |
1380 | 0 | return property_number; |
1381 | 0 | } |
1382 | | |
1383 | | /* Merge AArch64 GNU property BPROP with APROP also accounting for OUTPROP. |
1384 | | If APROP isn't NULL, merge it with BPROP and/or OUTPROP. Vice-versa if BROP |
1385 | | isn't NULL. Return TRUE if there is any update to APROP or if BPROP should |
1386 | | be merge with ABFD. */ |
1387 | | bool |
1388 | | _bfd_aarch64_elf_merge_gnu_properties (struct bfd_link_info *info |
1389 | | ATTRIBUTE_UNUSED, |
1390 | | bfd *abfd ATTRIBUTE_UNUSED, |
1391 | | elf_property *aprop, |
1392 | | elf_property *bprop, |
1393 | | uint32_t outprop) |
1394 | 0 | { |
1395 | 0 | unsigned int orig_number; |
1396 | 0 | bool updated = false; |
1397 | 0 | unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type; |
1398 | |
|
1399 | 0 | switch (pr_type) |
1400 | 0 | { |
1401 | 0 | case GNU_PROPERTY_AARCH64_FEATURE_1_AND: |
1402 | 0 | { |
1403 | 0 | aarch64_gcs_type gcs_type |
1404 | 0 | = elf_aarch64_tdata (info->output_bfd)->sw_protections.gcs_type; |
1405 | | /* OUTPROP does not contain GCS for GCS_NEVER. We only need to make sure |
1406 | | that APROP does not contain GCS as well. |
1407 | | Notes: |
1408 | | - if BPROP contains GCS and APROP is not null, it is zeroed by the |
1409 | | AND with APROP. |
1410 | | - if BPROP contains GCS and APROP is null, it is overwritten with |
1411 | | OUTPROP as the AND with APROP would have been equivalent to zeroing |
1412 | | BPROP. */ |
1413 | 0 | if (gcs_type == GCS_NEVER && aprop != NULL) |
1414 | 0 | aprop->u.number &= ~GNU_PROPERTY_AARCH64_FEATURE_1_GCS; |
1415 | |
|
1416 | 0 | if (aprop != NULL && bprop != NULL) |
1417 | 0 | { |
1418 | 0 | orig_number = aprop->u.number; |
1419 | 0 | aprop->u.number = (orig_number & bprop->u.number) | outprop; |
1420 | 0 | updated = orig_number != aprop->u.number; |
1421 | | /* Remove the property if all feature bits are cleared. */ |
1422 | 0 | if (aprop->u.number == 0) |
1423 | 0 | aprop->pr_kind = property_remove; |
1424 | 0 | break; |
1425 | 0 | } |
1426 | | /* If either is NULL, the AND would be 0 so, if there is |
1427 | | any OUTPROP, assign it to the input that is not NULL. */ |
1428 | 0 | if (outprop) |
1429 | 0 | { |
1430 | 0 | if (aprop != NULL) |
1431 | 0 | { |
1432 | 0 | orig_number = aprop->u.number; |
1433 | 0 | aprop->u.number = outprop; |
1434 | 0 | updated = orig_number != aprop->u.number; |
1435 | 0 | } |
1436 | 0 | else |
1437 | 0 | { |
1438 | 0 | bprop->u.number = outprop; |
1439 | 0 | updated = true; |
1440 | 0 | } |
1441 | 0 | } |
1442 | | /* No OUTPROP and BPROP is NULL, so remove APROP. */ |
1443 | 0 | else if (aprop != NULL) |
1444 | 0 | { |
1445 | 0 | aprop->pr_kind = property_remove; |
1446 | 0 | updated = true; |
1447 | 0 | } |
1448 | 0 | } |
1449 | 0 | break; |
1450 | | |
1451 | 0 | default: |
1452 | 0 | abort (); |
1453 | 0 | } |
1454 | | |
1455 | 0 | return updated; |
1456 | 0 | } |
1457 | | |
1458 | | /* Fix up AArch64 GNU properties. */ |
1459 | | void |
1460 | | _bfd_aarch64_elf_link_fixup_gnu_properties |
1461 | | (struct bfd_link_info *info ATTRIBUTE_UNUSED, |
1462 | | elf_property_list **listp) |
1463 | 0 | { |
1464 | 0 | elf_property_list *p, *prev; |
1465 | |
|
1466 | 0 | for (p = *listp, prev = *listp; p; p = p->next) |
1467 | 0 | { |
1468 | 0 | unsigned int type = p->property.pr_type; |
1469 | 0 | if (type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) |
1470 | 0 | { |
1471 | 0 | if (p->property.pr_kind == property_remove) |
1472 | 0 | { |
1473 | | /* Remove empty property. */ |
1474 | 0 | if (prev == p) |
1475 | 0 | { |
1476 | 0 | *listp = p->next; |
1477 | 0 | prev = *listp; |
1478 | 0 | } |
1479 | 0 | else |
1480 | 0 | prev->next = p->next; |
1481 | 0 | continue; |
1482 | 0 | } |
1483 | 0 | prev = p; |
1484 | 0 | } |
1485 | 0 | else if (type > GNU_PROPERTY_HIPROC) |
1486 | 0 | { |
1487 | | /* The property list is sorted in order of type. */ |
1488 | 0 | break; |
1489 | 0 | } |
1490 | 0 | } |
1491 | 0 | } |
1492 | | |
1493 | | /* Check AArch64 BTI report. */ |
1494 | | void |
1495 | | _bfd_aarch64_elf_check_bti_report (const struct bfd_link_info *info, |
1496 | | const bfd *abfd) |
1497 | 0 | { |
1498 | 0 | struct elf_aarch64_obj_tdata *tdata = elf_aarch64_tdata (info->output_bfd); |
1499 | |
|
1500 | 0 | if (elf_aarch64_tdata (info->output_bfd)->oa_merge_done |
1501 | 0 | || tdata->sw_protections.bti_report == MARKING_NONE) |
1502 | 0 | return; |
1503 | | |
1504 | 0 | ++tdata->n_bti_issues; |
1505 | |
|
1506 | 0 | if (tdata->n_bti_issues > GNU_PROPERTY_ISSUES_MAX) |
1507 | 0 | return; |
1508 | | |
1509 | 0 | const char *msg |
1510 | 0 | = (tdata->sw_protections.bti_report == MARKING_WARN) |
1511 | 0 | ? _("%pB: warning: BTI is required by -z force-bti, but this input object " |
1512 | 0 | "file lacks the necessary property note.\n") |
1513 | 0 | : _("%X%pB: error: BTI is required by -z force-bti, but this input object " |
1514 | 0 | "file lacks the necessary property note.\n"); |
1515 | |
|
1516 | 0 | info->callbacks->einfo (msg, abfd); |
1517 | 0 | } |
1518 | | |
1519 | | /* Check AArch64 GCS report. */ |
1520 | | void |
1521 | | _bfd_aarch64_elf_check_gcs_report (const struct bfd_link_info *info, |
1522 | | const bfd *abfd) |
1523 | 0 | { |
1524 | 0 | struct elf_aarch64_obj_tdata *tdata = elf_aarch64_tdata (info->output_bfd); |
1525 | 0 | bool dynamic_obj = (abfd->flags & DYNAMIC) != 0; |
1526 | |
|
1527 | 0 | if (dynamic_obj) |
1528 | 0 | { |
1529 | 0 | if (tdata->sw_protections.gcs_report_dynamic == MARKING_NONE) |
1530 | 0 | return; |
1531 | 0 | ++tdata->n_gcs_dynamic_issues; |
1532 | 0 | if (tdata->n_gcs_dynamic_issues > GNU_PROPERTY_ISSUES_MAX) |
1533 | 0 | return; |
1534 | 0 | } |
1535 | 0 | else |
1536 | 0 | { |
1537 | 0 | if (elf_aarch64_tdata (info->output_bfd)->oa_merge_done |
1538 | 0 | || tdata->sw_protections.gcs_report == MARKING_NONE) |
1539 | 0 | return; |
1540 | 0 | ++tdata->n_gcs_issues; |
1541 | 0 | if (tdata->n_gcs_issues > GNU_PROPERTY_ISSUES_MAX) |
1542 | 0 | return; |
1543 | 0 | } |
1544 | | |
1545 | 0 | const char *msg; |
1546 | 0 | if (dynamic_obj) |
1547 | 0 | msg = (tdata->sw_protections.gcs_report_dynamic == MARKING_WARN) |
1548 | 0 | ? _("%pB: warning: GCS is required by -z gcs, but this shared library " |
1549 | 0 | "lacks the necessary property note. The dynamic loader might not " |
1550 | 0 | "enable GCS or refuse to load the program unless all the shared " |
1551 | 0 | "library dependencies have the GCS marking.\n") |
1552 | 0 | : _("%X%pB: error: GCS is required by -z gcs, but this shared library " |
1553 | 0 | "lacks the necessary property note. The dynamic loader might not " |
1554 | 0 | "enable GCS or refuse to load the program unless all the shared " |
1555 | 0 | "library dependencies have the GCS marking.\n"); |
1556 | 0 | else |
1557 | 0 | msg = (tdata->sw_protections.gcs_report == MARKING_WARN) |
1558 | 0 | ? _("%pB: warning: GCS is required by -z gcs, but this input object file " |
1559 | 0 | "lacks the necessary property note.\n") |
1560 | 0 | : _("%X%pB: error: GCS is required by -z gcs, but this input object file " |
1561 | 0 | "lacks the necessary property note.\n"); |
1562 | |
|
1563 | 0 | info->callbacks->einfo (msg, abfd); |
1564 | 0 | } |