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