/src/binutils-gdb/bfd/elfxx-aarch64.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* AArch64-specific support for ELF. |
2 | | Copyright (C) 2009-2023 Free Software Foundation, Inc. |
3 | | Contributed by ARM Ltd. |
4 | | |
5 | | This file is part of BFD, the Binary File Descriptor library. |
6 | | |
7 | | This program is free software; you can redistribute it and/or modify |
8 | | it under the terms of the GNU General Public License as published by |
9 | | the Free Software Foundation; either version 3 of the License, or |
10 | | (at your option) any later version. |
11 | | |
12 | | This program is distributed in the hope that it will be useful, |
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | GNU General Public License for more details. |
16 | | |
17 | | You should have received a copy of the GNU General Public License |
18 | | along with this program; see the file COPYING3. If not, |
19 | | see <http://www.gnu.org/licenses/>. */ |
20 | | |
21 | | #include "sysdep.h" |
22 | | #include "bfd.h" |
23 | | #include "elf-bfd.h" |
24 | | #include "elfxx-aarch64.h" |
25 | | #include <stdarg.h> |
26 | | #include <string.h> |
27 | | |
28 | 0 | #define MASK(n) ((1u << (n)) - 1) |
29 | | |
30 | | /* Sign-extend VALUE, which has the indicated number of BITS. */ |
31 | | |
32 | | bfd_signed_vma |
33 | | _bfd_aarch64_sign_extend (bfd_vma value, int bits) |
34 | 0 | { |
35 | 0 | if (value & ((bfd_vma) 1 << (bits - 1))) |
36 | | /* VALUE is negative. */ |
37 | 0 | value |= ((bfd_vma) - 1) << bits; |
38 | |
|
39 | 0 | return value; |
40 | 0 | } |
41 | | |
42 | | /* Decode the IMM field of ADRP. */ |
43 | | |
44 | | uint32_t |
45 | | _bfd_aarch64_decode_adrp_imm (uint32_t insn) |
46 | 0 | { |
47 | 0 | return (((insn >> 5) & MASK (19)) << 2) | ((insn >> 29) & MASK (2)); |
48 | 0 | } |
49 | | |
50 | | /* Reencode the imm field of add immediate. */ |
51 | | static inline uint32_t |
52 | | reencode_add_imm (uint32_t insn, uint32_t imm) |
53 | 0 | { |
54 | 0 | return (insn & ~(MASK (12) << 10)) | ((imm & MASK (12)) << 10); |
55 | 0 | } |
56 | | |
57 | | /* Reencode the IMM field of ADR. */ |
58 | | |
59 | | uint32_t |
60 | | _bfd_aarch64_reencode_adr_imm (uint32_t insn, uint32_t imm) |
61 | 0 | { |
62 | 0 | return (insn & ~((MASK (2) << 29) | (MASK (19) << 5))) |
63 | 0 | | ((imm & MASK (2)) << 29) | ((imm & (MASK (19) << 2)) << 3); |
64 | 0 | } |
65 | | |
66 | | /* Reencode the imm field of ld/st pos immediate. */ |
67 | | static inline uint32_t |
68 | | reencode_ldst_pos_imm (uint32_t insn, uint32_t imm) |
69 | 0 | { |
70 | 0 | return (insn & ~(MASK (12) << 10)) | ((imm & MASK (12)) << 10); |
71 | 0 | } |
72 | | |
73 | | /* Encode the 26-bit offset of unconditional branch. */ |
74 | | static inline uint32_t |
75 | | reencode_branch_ofs_26 (uint32_t insn, uint32_t ofs) |
76 | 0 | { |
77 | 0 | return (insn & ~MASK (26)) | (ofs & MASK (26)); |
78 | 0 | } |
79 | | |
80 | | /* Encode the 19-bit offset of conditional branch and compare & branch. */ |
81 | | static inline uint32_t |
82 | | reencode_cond_branch_ofs_19 (uint32_t insn, uint32_t ofs) |
83 | 0 | { |
84 | 0 | return (insn & ~(MASK (19) << 5)) | ((ofs & MASK (19)) << 5); |
85 | 0 | } |
86 | | |
87 | | /* Decode the 19-bit offset of load literal. */ |
88 | | static inline uint32_t |
89 | | reencode_ld_lit_ofs_19 (uint32_t insn, uint32_t ofs) |
90 | 0 | { |
91 | 0 | return (insn & ~(MASK (19) << 5)) | ((ofs & MASK (19)) << 5); |
92 | 0 | } |
93 | | |
94 | | /* Encode the 14-bit offset of test & branch. */ |
95 | | static inline uint32_t |
96 | | reencode_tst_branch_ofs_14 (uint32_t insn, uint32_t ofs) |
97 | 0 | { |
98 | 0 | return (insn & ~(MASK (14) << 5)) | ((ofs & MASK (14)) << 5); |
99 | 0 | } |
100 | | |
101 | | /* Reencode the imm field of move wide. */ |
102 | | static inline uint32_t |
103 | | reencode_movw_imm (uint32_t insn, uint32_t imm) |
104 | 0 | { |
105 | 0 | return (insn & ~(MASK (16) << 5)) | ((imm & MASK (16)) << 5); |
106 | 0 | } |
107 | | |
108 | | /* Reencode mov[zn] to movz. */ |
109 | | static inline uint32_t |
110 | | reencode_movzn_to_movz (uint32_t opcode) |
111 | 0 | { |
112 | 0 | return opcode | (1 << 30); |
113 | 0 | } |
114 | | |
115 | | /* Reencode mov[zn] to movn. */ |
116 | | static inline uint32_t |
117 | | reencode_movzn_to_movn (uint32_t opcode) |
118 | 0 | { |
119 | 0 | return opcode & ~(1 << 30); |
120 | 0 | } |
121 | | |
122 | | /* Return non-zero if the indicated VALUE has overflowed the maximum |
123 | | range expressible by a unsigned number with the indicated number of |
124 | | BITS. */ |
125 | | |
126 | | static bfd_reloc_status_type |
127 | | aarch64_unsigned_overflow (bfd_vma value, unsigned int bits) |
128 | 0 | { |
129 | 0 | bfd_vma lim; |
130 | 0 | if (bits >= sizeof (bfd_vma) * 8) |
131 | 0 | return bfd_reloc_ok; |
132 | 0 | lim = (bfd_vma) 1 << bits; |
133 | 0 | if (value >= lim) |
134 | 0 | return bfd_reloc_overflow; |
135 | 0 | return bfd_reloc_ok; |
136 | 0 | } |
137 | | |
138 | | /* Return non-zero if the indicated VALUE has overflowed the maximum |
139 | | range expressible by an signed number with the indicated number of |
140 | | BITS. */ |
141 | | |
142 | | static bfd_reloc_status_type |
143 | | aarch64_signed_overflow (bfd_vma value, unsigned int bits) |
144 | 0 | { |
145 | 0 | bfd_signed_vma svalue = (bfd_signed_vma) value; |
146 | 0 | bfd_signed_vma lim; |
147 | |
|
148 | 0 | if (bits >= sizeof (bfd_vma) * 8) |
149 | 0 | return bfd_reloc_ok; |
150 | 0 | lim = (bfd_signed_vma) 1 << (bits - 1); |
151 | 0 | if (svalue < -lim || svalue >= lim) |
152 | 0 | return bfd_reloc_overflow; |
153 | 0 | return bfd_reloc_ok; |
154 | 0 | } |
155 | | |
156 | | /* Insert the addend/value into the instruction or data object being |
157 | | relocated. */ |
158 | | bfd_reloc_status_type |
159 | | _bfd_aarch64_elf_put_addend (bfd *abfd, |
160 | | bfd_byte *address, bfd_reloc_code_real_type r_type, |
161 | | reloc_howto_type *howto, bfd_signed_vma addend) |
162 | 0 | { |
163 | 0 | bfd_reloc_status_type status = bfd_reloc_ok; |
164 | 0 | bfd_signed_vma old_addend = addend; |
165 | 0 | bfd_vma contents; |
166 | 0 | int size; |
167 | |
|
168 | 0 | size = bfd_get_reloc_size (howto); |
169 | 0 | switch (size) |
170 | 0 | { |
171 | 0 | case 0: |
172 | 0 | return status; |
173 | 0 | case 2: |
174 | 0 | contents = bfd_get_16 (abfd, address); |
175 | 0 | break; |
176 | 0 | case 4: |
177 | 0 | if (howto->src_mask != 0xffffffff) |
178 | | /* Must be 32-bit instruction, always little-endian. */ |
179 | 0 | contents = bfd_getl32 (address); |
180 | 0 | else |
181 | | /* Must be 32-bit data (endianness dependent). */ |
182 | 0 | contents = bfd_get_32 (abfd, address); |
183 | 0 | break; |
184 | 0 | case 8: |
185 | 0 | contents = bfd_get_64 (abfd, address); |
186 | 0 | break; |
187 | 0 | default: |
188 | 0 | abort (); |
189 | 0 | } |
190 | | |
191 | 0 | switch (howto->complain_on_overflow) |
192 | 0 | { |
193 | 0 | case complain_overflow_dont: |
194 | 0 | break; |
195 | 0 | case complain_overflow_signed: |
196 | 0 | status = aarch64_signed_overflow (addend, |
197 | 0 | howto->bitsize + howto->rightshift); |
198 | 0 | break; |
199 | 0 | case complain_overflow_unsigned: |
200 | 0 | status = aarch64_unsigned_overflow (addend, |
201 | 0 | howto->bitsize + howto->rightshift); |
202 | 0 | break; |
203 | 0 | case complain_overflow_bitfield: |
204 | 0 | default: |
205 | 0 | abort (); |
206 | 0 | } |
207 | | |
208 | 0 | addend >>= howto->rightshift; |
209 | |
|
210 | 0 | switch (r_type) |
211 | 0 | { |
212 | 0 | case BFD_RELOC_AARCH64_CALL26: |
213 | 0 | case BFD_RELOC_AARCH64_JUMP26: |
214 | 0 | contents = reencode_branch_ofs_26 (contents, addend); |
215 | 0 | break; |
216 | | |
217 | 0 | case BFD_RELOC_AARCH64_BRANCH19: |
218 | 0 | contents = reencode_cond_branch_ofs_19 (contents, addend); |
219 | 0 | break; |
220 | | |
221 | 0 | case BFD_RELOC_AARCH64_TSTBR14: |
222 | 0 | contents = reencode_tst_branch_ofs_14 (contents, addend); |
223 | 0 | break; |
224 | | |
225 | 0 | case BFD_RELOC_AARCH64_GOT_LD_PREL19: |
226 | 0 | case BFD_RELOC_AARCH64_LD_LO19_PCREL: |
227 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19: |
228 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19: |
229 | 0 | if (old_addend & ((1 << howto->rightshift) - 1)) |
230 | 0 | return bfd_reloc_overflow; |
231 | 0 | contents = reencode_ld_lit_ofs_19 (contents, addend); |
232 | 0 | break; |
233 | | |
234 | 0 | case BFD_RELOC_AARCH64_TLSDESC_CALL: |
235 | 0 | break; |
236 | | |
237 | 0 | case BFD_RELOC_AARCH64_ADR_GOT_PAGE: |
238 | 0 | case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL: |
239 | 0 | case BFD_RELOC_AARCH64_ADR_HI21_PCREL: |
240 | 0 | case BFD_RELOC_AARCH64_ADR_LO21_PCREL: |
241 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21: |
242 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21: |
243 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21: |
244 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21: |
245 | 0 | case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: |
246 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21: |
247 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21: |
248 | 0 | contents = _bfd_aarch64_reencode_adr_imm (contents, addend); |
249 | 0 | break; |
250 | | |
251 | 0 | case BFD_RELOC_AARCH64_ADD_LO12: |
252 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12: |
253 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC: |
254 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_HI12: |
255 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12: |
256 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: |
257 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC: |
258 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12: |
259 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12: |
260 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC: |
261 | | /* Corresponds to: add rd, rn, #uimm12 to provide the low order |
262 | | 12 bits of the page offset following |
263 | | BFD_RELOC_AARCH64_ADR_HI21_PCREL which computes the |
264 | | (pc-relative) page base. */ |
265 | 0 | contents = reencode_add_imm (contents, addend); |
266 | 0 | break; |
267 | | |
268 | 0 | case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14: |
269 | 0 | case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC: |
270 | 0 | case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15: |
271 | 0 | case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15: |
272 | 0 | case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC: |
273 | 0 | case BFD_RELOC_AARCH64_LDST128_LO12: |
274 | 0 | case BFD_RELOC_AARCH64_LDST16_LO12: |
275 | 0 | case BFD_RELOC_AARCH64_LDST32_LO12: |
276 | 0 | case BFD_RELOC_AARCH64_LDST64_LO12: |
277 | 0 | case BFD_RELOC_AARCH64_LDST8_LO12: |
278 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC: |
279 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12: |
280 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC: |
281 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: |
282 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12: |
283 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC: |
284 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12: |
285 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC: |
286 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12: |
287 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC: |
288 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12: |
289 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC: |
290 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12: |
291 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: |
292 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12: |
293 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: |
294 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12: |
295 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: |
296 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12: |
297 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: |
298 | 0 | if (old_addend & ((1 << howto->rightshift) - 1)) |
299 | 0 | return bfd_reloc_overflow; |
300 | | /* Used for ldr*|str* rt, [rn, #uimm12] to provide the low order |
301 | | 12 bits address offset. */ |
302 | 0 | contents = reencode_ldst_pos_imm (contents, addend); |
303 | 0 | break; |
304 | | |
305 | | /* Group relocations to create high bits of a 16, 32, 48 or 64 |
306 | | bit signed data or abs address inline. Will change |
307 | | instruction to MOVN or MOVZ depending on sign of calculated |
308 | | value. */ |
309 | | |
310 | 0 | case BFD_RELOC_AARCH64_MOVW_G0_S: |
311 | 0 | case BFD_RELOC_AARCH64_MOVW_G1_S: |
312 | 0 | case BFD_RELOC_AARCH64_MOVW_G2_S: |
313 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G0: |
314 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G1: |
315 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G2: |
316 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G3: |
317 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0: |
318 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1: |
319 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2: |
320 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0: |
321 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1: |
322 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2: |
323 | | /* NOTE: We can only come here with movz or movn. */ |
324 | 0 | if (addend < 0) |
325 | 0 | { |
326 | | /* Force use of MOVN. */ |
327 | 0 | addend = ~addend; |
328 | 0 | contents = reencode_movzn_to_movn (contents); |
329 | 0 | } |
330 | 0 | else |
331 | 0 | { |
332 | | /* Force use of MOVZ. */ |
333 | 0 | contents = reencode_movzn_to_movz (contents); |
334 | 0 | } |
335 | | /* Fall through. */ |
336 | | |
337 | | /* Group relocations to create a 16, 32, 48 or 64 bit unsigned |
338 | | data or abs address inline. */ |
339 | |
|
340 | 0 | case BFD_RELOC_AARCH64_MOVW_G0: |
341 | 0 | case BFD_RELOC_AARCH64_MOVW_G0_NC: |
342 | 0 | case BFD_RELOC_AARCH64_MOVW_G1: |
343 | 0 | case BFD_RELOC_AARCH64_MOVW_G1_NC: |
344 | 0 | case BFD_RELOC_AARCH64_MOVW_G2: |
345 | 0 | case BFD_RELOC_AARCH64_MOVW_G2_NC: |
346 | 0 | case BFD_RELOC_AARCH64_MOVW_G3: |
347 | 0 | case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC: |
348 | 0 | case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1: |
349 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G0_NC: |
350 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G1_NC: |
351 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G2_NC: |
352 | 0 | case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC: |
353 | 0 | case BFD_RELOC_AARCH64_TLSDESC_OFF_G1: |
354 | 0 | case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC: |
355 | 0 | case BFD_RELOC_AARCH64_TLSGD_MOVW_G1: |
356 | 0 | case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC: |
357 | 0 | case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1: |
358 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: |
359 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC: |
360 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC: |
361 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC: |
362 | 0 | contents = reencode_movw_imm (contents, addend); |
363 | 0 | break; |
364 | | |
365 | 0 | default: |
366 | | /* Repack simple data */ |
367 | 0 | if (howto->dst_mask & (howto->dst_mask + 1)) |
368 | 0 | return bfd_reloc_notsupported; |
369 | | |
370 | 0 | contents = ((contents & ~howto->dst_mask) | (addend & howto->dst_mask)); |
371 | 0 | break; |
372 | 0 | } |
373 | | |
374 | 0 | switch (size) |
375 | 0 | { |
376 | 0 | case 2: |
377 | 0 | bfd_put_16 (abfd, contents, address); |
378 | 0 | break; |
379 | 0 | case 4: |
380 | 0 | if (howto->dst_mask != 0xffffffff) |
381 | | /* must be 32-bit instruction, always little-endian */ |
382 | 0 | bfd_putl32 (contents, address); |
383 | 0 | else |
384 | | /* must be 32-bit data (endianness dependent) */ |
385 | 0 | bfd_put_32 (abfd, contents, address); |
386 | 0 | break; |
387 | 0 | case 8: |
388 | 0 | bfd_put_64 (abfd, contents, address); |
389 | 0 | break; |
390 | 0 | default: |
391 | 0 | abort (); |
392 | 0 | } |
393 | | |
394 | 0 | return status; |
395 | 0 | } |
396 | | |
397 | | bfd_vma |
398 | | _bfd_aarch64_elf_resolve_relocation (bfd *input_bfd, |
399 | | bfd_reloc_code_real_type r_type, |
400 | | bfd_vma place, bfd_vma value, |
401 | | bfd_vma addend, bool weak_undef_p) |
402 | 0 | { |
403 | 0 | bool tls_reloc = true; |
404 | 0 | switch (r_type) |
405 | 0 | { |
406 | 0 | case BFD_RELOC_AARCH64_NONE: |
407 | 0 | case BFD_RELOC_AARCH64_TLSDESC_CALL: |
408 | 0 | break; |
409 | | |
410 | 0 | case BFD_RELOC_AARCH64_16_PCREL: |
411 | 0 | case BFD_RELOC_AARCH64_32_PCREL: |
412 | 0 | case BFD_RELOC_AARCH64_64_PCREL: |
413 | 0 | case BFD_RELOC_AARCH64_ADR_LO21_PCREL: |
414 | 0 | case BFD_RELOC_AARCH64_BRANCH19: |
415 | 0 | case BFD_RELOC_AARCH64_LD_LO19_PCREL: |
416 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G0: |
417 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G0_NC: |
418 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G1: |
419 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G1_NC: |
420 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G2: |
421 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G2_NC: |
422 | 0 | case BFD_RELOC_AARCH64_MOVW_PREL_G3: |
423 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21: |
424 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19: |
425 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21: |
426 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19: |
427 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21: |
428 | 0 | case BFD_RELOC_AARCH64_TSTBR14: |
429 | 0 | if (weak_undef_p) |
430 | 0 | value = place; |
431 | 0 | value = value + addend - place; |
432 | 0 | break; |
433 | | |
434 | 0 | case BFD_RELOC_AARCH64_CALL26: |
435 | 0 | case BFD_RELOC_AARCH64_JUMP26: |
436 | 0 | value = value + addend - place; |
437 | 0 | break; |
438 | | |
439 | 0 | case BFD_RELOC_AARCH64_16: |
440 | 0 | case BFD_RELOC_AARCH64_32: |
441 | 0 | case BFD_RELOC_AARCH64_MOVW_G0: |
442 | 0 | case BFD_RELOC_AARCH64_MOVW_G0_NC: |
443 | 0 | case BFD_RELOC_AARCH64_MOVW_G0_S: |
444 | 0 | case BFD_RELOC_AARCH64_MOVW_G1: |
445 | 0 | case BFD_RELOC_AARCH64_MOVW_G1_NC: |
446 | 0 | case BFD_RELOC_AARCH64_MOVW_G1_S: |
447 | 0 | case BFD_RELOC_AARCH64_MOVW_G2: |
448 | 0 | case BFD_RELOC_AARCH64_MOVW_G2_NC: |
449 | 0 | case BFD_RELOC_AARCH64_MOVW_G2_S: |
450 | 0 | case BFD_RELOC_AARCH64_MOVW_G3: |
451 | 0 | tls_reloc = false; |
452 | | /* fall-through. */ |
453 | 0 | case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC: |
454 | 0 | case BFD_RELOC_AARCH64_TLSDESC_OFF_G1: |
455 | 0 | case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC: |
456 | 0 | case BFD_RELOC_AARCH64_TLSGD_MOVW_G1: |
457 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_HI12: |
458 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12: |
459 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADD_DTPREL_LO12_NC: |
460 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12: |
461 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12: |
462 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12: |
463 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12: |
464 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0: |
465 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G0_NC: |
466 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1: |
467 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC: |
468 | 0 | case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2: |
469 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12: |
470 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12: |
471 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12: |
472 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12: |
473 | | /* Weak Symbols and TLS relocations are implementation defined. For this |
474 | | case we choose to emit 0. */ |
475 | 0 | if (weak_undef_p && tls_reloc) |
476 | 0 | { |
477 | 0 | _bfd_error_handler (_("%pB: warning: Weak TLS is implementation " |
478 | 0 | "defined and may not work as expected"), |
479 | 0 | input_bfd); |
480 | 0 | value = place; |
481 | 0 | } |
482 | 0 | value = value + addend; |
483 | 0 | break; |
484 | | |
485 | 0 | case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL: |
486 | 0 | case BFD_RELOC_AARCH64_ADR_HI21_PCREL: |
487 | 0 | if (weak_undef_p) |
488 | 0 | value = PG (place); |
489 | 0 | value = PG (value + addend) - PG (place); |
490 | 0 | break; |
491 | | |
492 | 0 | case BFD_RELOC_AARCH64_GOT_LD_PREL19: |
493 | 0 | value = value + addend - place; |
494 | 0 | break; |
495 | | |
496 | 0 | case BFD_RELOC_AARCH64_ADR_GOT_PAGE: |
497 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21: |
498 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21: |
499 | 0 | case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: |
500 | 0 | case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21: |
501 | 0 | value = PG (value + addend) - PG (place); |
502 | 0 | break; |
503 | | |
504 | | /* Caller must make sure addend is the base address of .got section. */ |
505 | 0 | case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14: |
506 | 0 | case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15: |
507 | 0 | addend = PG (addend); |
508 | | /* Fall through. */ |
509 | 0 | case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15: |
510 | 0 | case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC: |
511 | 0 | case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1: |
512 | 0 | value = value - addend; |
513 | 0 | break; |
514 | | |
515 | 0 | case BFD_RELOC_AARCH64_ADD_LO12: |
516 | 0 | case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC: |
517 | 0 | case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC: |
518 | 0 | case BFD_RELOC_AARCH64_LDST128_LO12: |
519 | 0 | case BFD_RELOC_AARCH64_LDST16_LO12: |
520 | 0 | case BFD_RELOC_AARCH64_LDST32_LO12: |
521 | 0 | case BFD_RELOC_AARCH64_LDST64_LO12: |
522 | 0 | case BFD_RELOC_AARCH64_LDST8_LO12: |
523 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADD: |
524 | 0 | case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12: |
525 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC: |
526 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12: |
527 | 0 | case BFD_RELOC_AARCH64_TLSDESC_LDR: |
528 | 0 | case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC: |
529 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC: |
530 | 0 | case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: |
531 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC: |
532 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC: |
533 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC: |
534 | 0 | case BFD_RELOC_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC: |
535 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12_NC: |
536 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: |
537 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: |
538 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: |
539 | 0 | case BFD_RELOC_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: |
540 | 0 | value = PG_OFFSET (value + addend); |
541 | 0 | break; |
542 | | |
543 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12: |
544 | 0 | value = value + addend; |
545 | 0 | break; |
546 | | |
547 | 0 | case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1: |
548 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1: |
549 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC: |
550 | 0 | value = (value + addend) & (bfd_vma) 0xffff0000; |
551 | 0 | break; |
552 | 0 | case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12: |
553 | | /* Mask off low 12bits, keep all other high bits, so that the later |
554 | | generic code could check whehter there is overflow. */ |
555 | 0 | value = (value + addend) & ~(bfd_vma) 0xfff; |
556 | 0 | break; |
557 | | |
558 | 0 | case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC: |
559 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0: |
560 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G0_NC: |
561 | 0 | value = (value + addend) & (bfd_vma) 0xffff; |
562 | 0 | break; |
563 | | |
564 | 0 | case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2: |
565 | 0 | value = (value + addend) & ~(bfd_vma) 0xffffffff; |
566 | 0 | value -= place & ~(bfd_vma) 0xffffffff; |
567 | 0 | break; |
568 | | |
569 | 0 | default: |
570 | 0 | break; |
571 | 0 | } |
572 | | |
573 | 0 | return value; |
574 | 0 | } |
575 | | |
576 | | /* Support for core dump NOTE sections. */ |
577 | | |
578 | | bool |
579 | | _bfd_aarch64_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) |
580 | 0 | { |
581 | 0 | int offset; |
582 | 0 | size_t size; |
583 | |
|
584 | 0 | switch (note->descsz) |
585 | 0 | { |
586 | 0 | default: |
587 | 0 | return false; |
588 | | |
589 | 0 | case 392: /* sizeof(struct elf_prstatus) on Linux/arm64. */ |
590 | | /* pr_cursig */ |
591 | 0 | elf_tdata (abfd)->core->signal |
592 | 0 | = bfd_get_16 (abfd, note->descdata + 12); |
593 | | |
594 | | /* pr_pid */ |
595 | 0 | elf_tdata (abfd)->core->lwpid |
596 | 0 | = bfd_get_32 (abfd, note->descdata + 32); |
597 | | |
598 | | /* pr_reg */ |
599 | 0 | offset = 112; |
600 | 0 | size = 272; |
601 | |
|
602 | 0 | break; |
603 | 0 | } |
604 | | |
605 | | /* Make a ".reg/999" section. */ |
606 | 0 | return _bfd_elfcore_make_pseudosection (abfd, ".reg", |
607 | 0 | size, note->descpos + offset); |
608 | 0 | } |
609 | | |
610 | | bool |
611 | | _bfd_aarch64_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) |
612 | 0 | { |
613 | 0 | switch (note->descsz) |
614 | 0 | { |
615 | 0 | default: |
616 | 0 | return false; |
617 | | |
618 | 0 | case 136: /* This is sizeof(struct elf_prpsinfo) on Linux/aarch64. */ |
619 | 0 | elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 24); |
620 | 0 | elf_tdata (abfd)->core->program |
621 | 0 | = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16); |
622 | 0 | elf_tdata (abfd)->core->command |
623 | 0 | = _bfd_elfcore_strndup (abfd, note->descdata + 56, 80); |
624 | 0 | } |
625 | | |
626 | | /* Note that for some reason, a spurious space is tacked |
627 | | onto the end of the args in some (at least one anyway) |
628 | | implementations, so strip it off if it exists. */ |
629 | | |
630 | 0 | { |
631 | 0 | char *command = elf_tdata (abfd)->core->command; |
632 | 0 | int n = strlen (command); |
633 | |
|
634 | 0 | if (0 < n && command[n - 1] == ' ') |
635 | 0 | command[n - 1] = '\0'; |
636 | 0 | } |
637 | |
|
638 | 0 | return true; |
639 | 0 | } |
640 | | |
641 | | char * |
642 | | _bfd_aarch64_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, |
643 | | ...) |
644 | 0 | { |
645 | 0 | switch (note_type) |
646 | 0 | { |
647 | 0 | default: |
648 | 0 | return NULL; |
649 | | |
650 | 0 | case NT_PRPSINFO: |
651 | 0 | { |
652 | 0 | char data[136] ATTRIBUTE_NONSTRING; |
653 | 0 | va_list ap; |
654 | |
|
655 | 0 | va_start (ap, note_type); |
656 | 0 | memset (data, 0, sizeof (data)); |
657 | 0 | strncpy (data + 40, va_arg (ap, const char *), 16); |
658 | | #if GCC_VERSION == 8000 || GCC_VERSION == 8001 |
659 | | DIAGNOSTIC_PUSH; |
660 | | /* GCC 8.0 and 8.1 warn about 80 equals destination size with |
661 | | -Wstringop-truncation: |
662 | | https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85643 |
663 | | */ |
664 | | DIAGNOSTIC_IGNORE_STRINGOP_TRUNCATION; |
665 | | #endif |
666 | 0 | strncpy (data + 56, va_arg (ap, const char *), 80); |
667 | | #if GCC_VERSION == 8000 || GCC_VERSION == 8001 |
668 | | DIAGNOSTIC_POP; |
669 | | #endif |
670 | 0 | va_end (ap); |
671 | |
|
672 | 0 | return elfcore_write_note (abfd, buf, bufsiz, "CORE", |
673 | 0 | note_type, data, sizeof (data)); |
674 | 0 | } |
675 | | |
676 | 0 | case NT_PRSTATUS: |
677 | 0 | { |
678 | 0 | char data[392]; |
679 | 0 | va_list ap; |
680 | 0 | long pid; |
681 | 0 | int cursig; |
682 | 0 | const void *greg; |
683 | |
|
684 | 0 | va_start (ap, note_type); |
685 | 0 | memset (data, 0, sizeof (data)); |
686 | 0 | pid = va_arg (ap, long); |
687 | 0 | bfd_put_32 (abfd, pid, data + 32); |
688 | 0 | cursig = va_arg (ap, int); |
689 | 0 | bfd_put_16 (abfd, cursig, data + 12); |
690 | 0 | greg = va_arg (ap, const void *); |
691 | 0 | memcpy (data + 112, greg, 272); |
692 | 0 | va_end (ap); |
693 | |
|
694 | 0 | return elfcore_write_note (abfd, buf, bufsiz, "CORE", |
695 | 0 | note_type, data, sizeof (data)); |
696 | 0 | } |
697 | 0 | } |
698 | 0 | } |
699 | | |
700 | | /* Find the first input bfd with GNU property and merge it with GPROP. If no |
701 | | such input is found, add it to a new section at the last input. Update |
702 | | GPROP accordingly. */ |
703 | | bfd * |
704 | | _bfd_aarch64_elf_link_setup_gnu_properties (struct bfd_link_info *info, |
705 | | uint32_t *gprop) |
706 | 0 | { |
707 | 0 | asection *sec; |
708 | 0 | bfd *pbfd; |
709 | 0 | bfd *ebfd = NULL; |
710 | 0 | elf_property *prop; |
711 | 0 | unsigned align; |
712 | |
|
713 | 0 | uint32_t gnu_prop = *gprop; |
714 | | |
715 | | /* Find a normal input file with GNU property note. */ |
716 | 0 | for (pbfd = info->input_bfds; |
717 | 0 | pbfd != NULL; |
718 | 0 | pbfd = pbfd->link.next) |
719 | 0 | if (bfd_get_flavour (pbfd) == bfd_target_elf_flavour |
720 | 0 | && bfd_count_sections (pbfd) != 0) |
721 | 0 | { |
722 | 0 | ebfd = pbfd; |
723 | |
|
724 | 0 | if (elf_properties (pbfd) != NULL) |
725 | 0 | break; |
726 | 0 | } |
727 | | |
728 | | /* If ebfd != NULL it is either an input with property note or the last |
729 | | input. Either way if we have gnu_prop, we should add it (by creating |
730 | | a section if needed). */ |
731 | 0 | if (ebfd != NULL && gnu_prop) |
732 | 0 | { |
733 | 0 | prop = _bfd_elf_get_property (ebfd, |
734 | 0 | GNU_PROPERTY_AARCH64_FEATURE_1_AND, |
735 | 0 | 4); |
736 | 0 | if (gnu_prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI |
737 | 0 | && !(prop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) |
738 | 0 | _bfd_error_handler (_("%pB: warning: BTI turned on by -z force-bti " |
739 | 0 | "when all inputs do not have BTI in NOTE " |
740 | 0 | "section."), ebfd); |
741 | 0 | prop->u.number |= gnu_prop; |
742 | 0 | prop->pr_kind = property_number; |
743 | | |
744 | | /* pbfd being NULL implies ebfd is the last input. Create the GNU |
745 | | property note section. */ |
746 | 0 | if (pbfd == NULL) |
747 | 0 | { |
748 | 0 | sec = bfd_make_section_with_flags (ebfd, |
749 | 0 | NOTE_GNU_PROPERTY_SECTION_NAME, |
750 | 0 | (SEC_ALLOC |
751 | 0 | | SEC_LOAD |
752 | 0 | | SEC_IN_MEMORY |
753 | 0 | | SEC_READONLY |
754 | 0 | | SEC_HAS_CONTENTS |
755 | 0 | | SEC_DATA)); |
756 | 0 | if (sec == NULL) |
757 | 0 | info->callbacks->einfo ( |
758 | 0 | _("%F%P: failed to create GNU property section\n")); |
759 | |
|
760 | 0 | align = (bfd_get_mach (ebfd) & bfd_mach_aarch64_ilp32) ? 2 : 3; |
761 | 0 | if (!bfd_set_section_alignment (sec, align)) |
762 | 0 | info->callbacks->einfo (_("%F%pA: failed to align section\n"), |
763 | 0 | sec); |
764 | |
|
765 | 0 | elf_section_type (sec) = SHT_NOTE; |
766 | 0 | } |
767 | 0 | } |
768 | |
|
769 | 0 | pbfd = _bfd_elf_link_setup_gnu_properties (info); |
770 | |
|
771 | 0 | if (bfd_link_relocatable (info)) |
772 | 0 | return pbfd; |
773 | | |
774 | | /* If pbfd has any GNU_PROPERTY_AARCH64_FEATURE_1_AND properties, update |
775 | | gnu_prop accordingly. */ |
776 | 0 | if (pbfd != NULL) |
777 | 0 | { |
778 | 0 | elf_property_list *p; |
779 | | |
780 | | /* The property list is sorted in order of type. */ |
781 | 0 | for (p = elf_properties (pbfd); p; p = p->next) |
782 | 0 | { |
783 | | /* Check for all GNU_PROPERTY_AARCH64_FEATURE_1_AND. */ |
784 | 0 | if (GNU_PROPERTY_AARCH64_FEATURE_1_AND == p->property.pr_type) |
785 | 0 | { |
786 | 0 | gnu_prop = (p->property.u.number |
787 | 0 | & (GNU_PROPERTY_AARCH64_FEATURE_1_PAC |
788 | 0 | | GNU_PROPERTY_AARCH64_FEATURE_1_BTI)); |
789 | 0 | break; |
790 | 0 | } |
791 | 0 | else if (GNU_PROPERTY_AARCH64_FEATURE_1_AND < p->property.pr_type) |
792 | 0 | break; |
793 | 0 | } |
794 | 0 | } |
795 | 0 | *gprop = gnu_prop; |
796 | 0 | return pbfd; |
797 | 0 | } |
798 | | |
799 | | /* Define elf_backend_parse_gnu_properties for AArch64. */ |
800 | | enum elf_property_kind |
801 | | _bfd_aarch64_elf_parse_gnu_properties (bfd *abfd, unsigned int type, |
802 | | bfd_byte *ptr, unsigned int datasz) |
803 | 0 | { |
804 | 0 | elf_property *prop; |
805 | |
|
806 | 0 | switch (type) |
807 | 0 | { |
808 | 0 | case GNU_PROPERTY_AARCH64_FEATURE_1_AND: |
809 | 0 | if (datasz != 4) |
810 | 0 | { |
811 | 0 | _bfd_error_handler |
812 | 0 | ( _("error: %pB: <corrupt AArch64 used size: 0x%x>"), |
813 | 0 | abfd, datasz); |
814 | 0 | return property_corrupt; |
815 | 0 | } |
816 | 0 | prop = _bfd_elf_get_property (abfd, type, datasz); |
817 | | /* Combine properties of the same type. */ |
818 | 0 | prop->u.number |= bfd_h_get_32 (abfd, ptr); |
819 | 0 | prop->pr_kind = property_number; |
820 | 0 | break; |
821 | | |
822 | 0 | default: |
823 | 0 | return property_ignored; |
824 | 0 | } |
825 | | |
826 | 0 | return property_number; |
827 | 0 | } |
828 | | |
829 | | /* Merge AArch64 GNU property BPROP with APROP also accounting for PROP. |
830 | | If APROP isn't NULL, merge it with BPROP and/or PROP. Vice-versa if BROP |
831 | | isn't NULL. Return TRUE if there is any update to APROP or if BPROP should |
832 | | be merge with ABFD. */ |
833 | | bool |
834 | | _bfd_aarch64_elf_merge_gnu_properties (struct bfd_link_info *info |
835 | | ATTRIBUTE_UNUSED, |
836 | | bfd *abfd ATTRIBUTE_UNUSED, |
837 | | elf_property *aprop, |
838 | | elf_property *bprop, |
839 | | uint32_t prop) |
840 | 0 | { |
841 | 0 | unsigned int orig_number; |
842 | 0 | bool updated = false; |
843 | 0 | unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type; |
844 | |
|
845 | 0 | switch (pr_type) |
846 | 0 | { |
847 | 0 | case GNU_PROPERTY_AARCH64_FEATURE_1_AND: |
848 | 0 | { |
849 | 0 | if (aprop != NULL && bprop != NULL) |
850 | 0 | { |
851 | 0 | orig_number = aprop->u.number; |
852 | 0 | aprop->u.number = (orig_number & bprop->u.number) | prop; |
853 | 0 | updated = orig_number != aprop->u.number; |
854 | | /* Remove the property if all feature bits are cleared. */ |
855 | 0 | if (aprop->u.number == 0) |
856 | 0 | aprop->pr_kind = property_remove; |
857 | 0 | break; |
858 | 0 | } |
859 | | /* If either is NULL, the AND would be 0 so, if there is |
860 | | any PROP, asign it to the input that is not NULL. */ |
861 | 0 | if (prop) |
862 | 0 | { |
863 | 0 | if (aprop != NULL) |
864 | 0 | { |
865 | 0 | orig_number = aprop->u.number; |
866 | 0 | aprop->u.number = prop; |
867 | 0 | updated = orig_number != aprop->u.number; |
868 | 0 | } |
869 | 0 | else |
870 | 0 | { |
871 | 0 | bprop->u.number = prop; |
872 | 0 | updated = true; |
873 | 0 | } |
874 | 0 | } |
875 | | /* No PROP and BPROP is NULL, so remove APROP. */ |
876 | 0 | else if (aprop != NULL) |
877 | 0 | { |
878 | 0 | aprop->pr_kind = property_remove; |
879 | 0 | updated = true; |
880 | 0 | } |
881 | 0 | } |
882 | 0 | break; |
883 | | |
884 | 0 | default: |
885 | 0 | abort (); |
886 | 0 | } |
887 | | |
888 | 0 | return updated; |
889 | 0 | } |
890 | | |
891 | | /* Fix up AArch64 GNU properties. */ |
892 | | void |
893 | | _bfd_aarch64_elf_link_fixup_gnu_properties |
894 | | (struct bfd_link_info *info ATTRIBUTE_UNUSED, |
895 | | elf_property_list **listp) |
896 | 0 | { |
897 | 0 | elf_property_list *p, *prev; |
898 | |
|
899 | 0 | for (p = *listp, prev = *listp; p; p = p->next) |
900 | 0 | { |
901 | 0 | unsigned int type = p->property.pr_type; |
902 | 0 | if (type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) |
903 | 0 | { |
904 | 0 | if (p->property.pr_kind == property_remove) |
905 | 0 | { |
906 | | /* Remove empty property. */ |
907 | 0 | if (prev == p) |
908 | 0 | { |
909 | 0 | *listp = p->next; |
910 | 0 | prev = *listp; |
911 | 0 | } |
912 | 0 | else |
913 | 0 | prev->next = p->next; |
914 | 0 | continue; |
915 | 0 | } |
916 | 0 | prev = p; |
917 | 0 | } |
918 | 0 | else if (type > GNU_PROPERTY_HIPROC) |
919 | 0 | { |
920 | | /* The property list is sorted in order of type. */ |
921 | 0 | break; |
922 | 0 | } |
923 | 0 | } |
924 | 0 | } |