/src/binutils-gdb/bfd/elf-properties.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* ELF program property support. |
2 | | Copyright (C) 2017-2025 Free Software Foundation, Inc. |
3 | | |
4 | | This file is part of BFD, the Binary File Descriptor library. |
5 | | |
6 | | This program is free software; you can redistribute it and/or modify |
7 | | it under the terms of the GNU General Public License as published by |
8 | | the Free Software Foundation; either version 3 of the License, or |
9 | | (at your option) any later version. |
10 | | |
11 | | This program is distributed in the hope that it will be useful, |
12 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | GNU General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with this program; if not, write to the Free Software |
18 | | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
19 | | MA 02110-1301, USA. */ |
20 | | |
21 | | /* GNU program property draft is at: |
22 | | |
23 | | https://github.com/hjl-tools/linux-abi/wiki/property-draft.pdf |
24 | | */ |
25 | | |
26 | | #include "sysdep.h" |
27 | | #include "bfd.h" |
28 | | #include "libbfd.h" |
29 | | #include "elf-bfd.h" |
30 | | |
31 | | /* Find a property. */ |
32 | | elf_property_list * |
33 | | _bfd_elf_find_property (elf_property_list *l, |
34 | | unsigned int type, |
35 | | elf_property_list **prev) |
36 | 411 | { |
37 | 411 | if (prev != NULL) |
38 | 411 | *prev = NULL; |
39 | | |
40 | | /* The properties are supposed to be sorted in the list. */ |
41 | 462 | for (elf_property_list *n = l; n != NULL; n = n->next) |
42 | 111 | { |
43 | 111 | if (type == n->property.pr_type) |
44 | 28 | return n; |
45 | 83 | else if (type < n->property.pr_type) |
46 | 32 | break; |
47 | 51 | else if (prev != NULL) |
48 | 51 | *prev = n; |
49 | 111 | } |
50 | 383 | return NULL; |
51 | 411 | } |
52 | | |
53 | | /* Insert a property into the list after prev. */ |
54 | | static elf_property_list * |
55 | | _bfd_elf_insert_property (elf_property_list *l, |
56 | | elf_property_list *what, |
57 | | elf_property_list *prev) |
58 | 383 | { |
59 | 383 | if (l == NULL) // First node. |
60 | 304 | return what; |
61 | | |
62 | 79 | if (prev == NULL) // Prepend. |
63 | 32 | { |
64 | 32 | what->next = l; |
65 | 32 | return what; |
66 | 32 | } |
67 | | |
68 | 47 | what->next = prev->next; |
69 | 47 | prev->next = what; |
70 | 47 | return l; |
71 | 79 | } |
72 | | |
73 | | /* Remove a property from the list after prev. */ |
74 | | static elf_property_list * |
75 | | _bfd_elf_remove_property (elf_property_list *l, |
76 | | elf_property_list *what, |
77 | | elf_property_list *prev) |
78 | 0 | { |
79 | 0 | if (l == NULL) |
80 | 0 | return l; |
81 | | |
82 | 0 | if (prev == NULL) // Pop front |
83 | 0 | { |
84 | 0 | BFD_ASSERT (what == l); |
85 | 0 | l = what->next; |
86 | 0 | } |
87 | 0 | else |
88 | 0 | prev->next = what->next; |
89 | |
|
90 | 0 | what->next = NULL; |
91 | 0 | return l; |
92 | 0 | } |
93 | | |
94 | | /* Get a property, allocate a new one if needed. */ |
95 | | |
96 | | elf_property * |
97 | | _bfd_elf_get_property (bfd *abfd, unsigned int type, unsigned int datasz) |
98 | 411 | { |
99 | 411 | if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) |
100 | 0 | { |
101 | | /* Never should happen. */ |
102 | 0 | abort (); |
103 | 0 | } |
104 | | |
105 | 411 | elf_property_list *prev; |
106 | 411 | elf_property_list *p = |
107 | 411 | _bfd_elf_find_property (elf_properties (abfd), type, &prev); |
108 | 411 | if (p != NULL) /* Reuse the existing entry. */ |
109 | 28 | { |
110 | 28 | if (datasz > p->property.pr_datasz) |
111 | 0 | { |
112 | | /* This can happen when mixing 32-bit and 64-bit objects. */ |
113 | 0 | p->property.pr_datasz = datasz; |
114 | 0 | } |
115 | 28 | return &p->property; |
116 | 28 | } |
117 | | |
118 | 383 | p = (elf_property_list *) bfd_alloc (abfd, sizeof (*p)); |
119 | 383 | if (p == NULL) |
120 | 0 | { |
121 | 0 | _bfd_error_handler (_("%pB: out of memory in _bfd_elf_get_property"), |
122 | 0 | abfd); |
123 | 0 | _exit (EXIT_FAILURE); |
124 | 0 | } |
125 | | |
126 | 383 | memset (p, 0, sizeof (*p)); |
127 | 383 | p->property.pr_type = type; |
128 | 383 | p->property.pr_datasz = datasz; |
129 | | |
130 | 383 | elf_properties (abfd) = |
131 | 383 | _bfd_elf_insert_property (elf_properties (abfd), p, prev); |
132 | | |
133 | 383 | return &p->property; |
134 | 383 | } |
135 | | |
136 | | /* Parse GNU properties. */ |
137 | | |
138 | | bool |
139 | | _bfd_elf_parse_gnu_properties (bfd *abfd, Elf_Internal_Note *note) |
140 | 652 | { |
141 | 652 | const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
142 | 652 | unsigned int align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4; |
143 | 652 | bfd_byte *ptr = (bfd_byte *) note->descdata; |
144 | 652 | bfd_byte *ptr_end = ptr + note->descsz; |
145 | | |
146 | 652 | if (note->descsz < 8 || (note->descsz % align_size) != 0) |
147 | 101 | { |
148 | 104 | bad_size: |
149 | 104 | _bfd_error_handler |
150 | 104 | (_("warning: %pB: corrupt GNU_PROPERTY_TYPE (%ld) size: %#lx"), |
151 | 104 | abfd, note->type, note->descsz); |
152 | 104 | return false; |
153 | 101 | } |
154 | | |
155 | 1.76k | while (ptr != ptr_end) |
156 | 1.55k | { |
157 | 1.55k | unsigned int type; |
158 | 1.55k | unsigned int datasz; |
159 | 1.55k | elf_property *prop; |
160 | | |
161 | 1.55k | if ((size_t) (ptr_end - ptr) < 8) |
162 | 3 | goto bad_size; |
163 | | |
164 | 1.55k | type = bfd_h_get_32 (abfd, ptr); |
165 | 1.55k | datasz = bfd_h_get_32 (abfd, ptr + 4); |
166 | 1.55k | ptr += 8; |
167 | | |
168 | 1.55k | if (datasz > (size_t) (ptr_end - ptr)) |
169 | 158 | { |
170 | 158 | _bfd_error_handler |
171 | 158 | (_("warning: %pB: corrupt GNU_PROPERTY_TYPE (%ld) type (0x%x) datasz: 0x%x"), |
172 | 158 | abfd, note->type, type, datasz); |
173 | | /* Clear all properties. */ |
174 | 158 | elf_properties (abfd) = NULL; |
175 | 158 | return false; |
176 | 158 | } |
177 | | |
178 | 1.39k | if (type >= GNU_PROPERTY_LOPROC) |
179 | 594 | { |
180 | 594 | if (bed->elf_machine_code == EM_NONE) |
181 | 132 | { |
182 | | /* Ignore processor-specific properties with generic ELF |
183 | | target vector. They should be handled by the matching |
184 | | ELF target vector. */ |
185 | 132 | goto next; |
186 | 132 | } |
187 | 462 | else if (type < GNU_PROPERTY_LOUSER |
188 | 462 | && bed->parse_gnu_properties) |
189 | 267 | { |
190 | 267 | enum elf_property_kind kind |
191 | 267 | = bed->parse_gnu_properties (abfd, type, ptr, datasz); |
192 | 267 | if (kind == property_corrupt) |
193 | 30 | { |
194 | | /* Clear all properties. */ |
195 | 30 | elf_properties (abfd) = NULL; |
196 | 30 | return false; |
197 | 30 | } |
198 | 237 | else if (kind != property_ignored) |
199 | 151 | goto next; |
200 | 267 | } |
201 | 594 | } |
202 | 799 | else |
203 | 799 | { |
204 | 799 | switch (type) |
205 | 799 | { |
206 | 189 | case GNU_PROPERTY_STACK_SIZE: |
207 | 189 | if (datasz != align_size) |
208 | 66 | { |
209 | 66 | _bfd_error_handler |
210 | 66 | (_("warning: %pB: corrupt stack size: 0x%x"), |
211 | 66 | abfd, datasz); |
212 | | /* Clear all properties. */ |
213 | 66 | elf_properties (abfd) = NULL; |
214 | 66 | return false; |
215 | 66 | } |
216 | 123 | prop = _bfd_elf_get_property (abfd, type, datasz); |
217 | 123 | if (datasz == 8) |
218 | 123 | prop->u.number = bfd_h_get_64 (abfd, ptr); |
219 | 0 | else |
220 | 0 | prop->u.number = bfd_h_get_32 (abfd, ptr); |
221 | 123 | prop->pr_kind = property_number; |
222 | 123 | goto next; |
223 | | |
224 | 72 | case GNU_PROPERTY_NO_COPY_ON_PROTECTED: |
225 | 72 | if (datasz != 0) |
226 | 34 | { |
227 | 34 | _bfd_error_handler |
228 | 34 | (_("warning: %pB: corrupt no copy on protected size: 0x%x"), |
229 | 34 | abfd, datasz); |
230 | | /* Clear all properties. */ |
231 | 34 | elf_properties (abfd) = NULL; |
232 | 34 | return false; |
233 | 34 | } |
234 | 38 | prop = _bfd_elf_get_property (abfd, type, datasz); |
235 | 38 | elf_has_no_copy_on_protected (abfd) = true; |
236 | 38 | prop->pr_kind = property_number; |
237 | 38 | goto next; |
238 | | |
239 | 60 | case GNU_PROPERTY_MEMORY_SEAL: |
240 | 60 | if (datasz != 0) |
241 | 23 | { |
242 | 23 | _bfd_error_handler |
243 | 23 | (_("warning: %pB: corrupt memory sealing size: 0x%x"), |
244 | 23 | abfd, datasz); |
245 | | /* Clear all properties. */ |
246 | 23 | elf_properties (abfd) = NULL; |
247 | 23 | return false; |
248 | 23 | } |
249 | 37 | prop = _bfd_elf_get_property (abfd, type, datasz); |
250 | 37 | prop->pr_kind = property_number; |
251 | 37 | goto next; |
252 | | |
253 | 478 | default: |
254 | 478 | if ((type >= GNU_PROPERTY_UINT32_AND_LO |
255 | 478 | && type <= GNU_PROPERTY_UINT32_AND_HI) |
256 | 478 | || (type >= GNU_PROPERTY_UINT32_OR_LO |
257 | 443 | && type <= GNU_PROPERTY_UINT32_OR_HI)) |
258 | 88 | { |
259 | 88 | if (datasz != 4) |
260 | 26 | { |
261 | 26 | _bfd_error_handler |
262 | 26 | (_("error: %pB: <corrupt property (0x%x) size: 0x%x>"), |
263 | 26 | abfd, type, datasz); |
264 | | /* Clear all properties. */ |
265 | 26 | elf_properties (abfd) = NULL; |
266 | 26 | return false; |
267 | 26 | } |
268 | 62 | prop = _bfd_elf_get_property (abfd, type, datasz); |
269 | 62 | prop->u.number |= bfd_h_get_32 (abfd, ptr); |
270 | 62 | prop->pr_kind = property_number; |
271 | 62 | if (type == GNU_PROPERTY_1_NEEDED |
272 | 62 | && ((prop->u.number |
273 | 36 | & GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS) |
274 | 36 | != 0)) |
275 | 19 | { |
276 | 19 | elf_has_indirect_extern_access (abfd) = true; |
277 | | /* GNU_PROPERTY_NO_COPY_ON_PROTECTED is implied. */ |
278 | 19 | elf_has_no_copy_on_protected (abfd) = true; |
279 | 19 | } |
280 | 62 | goto next; |
281 | 88 | } |
282 | 390 | break; |
283 | 799 | } |
284 | 799 | } |
285 | | |
286 | 671 | _bfd_error_handler |
287 | 671 | (_("warning: %pB: unsupported GNU_PROPERTY_TYPE (%ld) type: 0x%x"), |
288 | 671 | abfd, note->type, type); |
289 | | |
290 | 1.21k | next: |
291 | 1.21k | ptr += (datasz + (align_size - 1)) & ~ (align_size - 1); |
292 | 1.21k | } |
293 | | |
294 | 211 | return true; |
295 | 551 | } |
296 | | |
297 | | /* Merge GNU property BPROP with APROP. If APROP isn't NULL, return TRUE |
298 | | if APROP is updated. Otherwise, return TRUE if BPROP should be merged |
299 | | with ABFD. */ |
300 | | |
301 | | static bool |
302 | | elf_merge_gnu_properties (struct bfd_link_info *info, bfd *abfd, bfd *bbfd, |
303 | | elf_property *aprop, elf_property *bprop) |
304 | 0 | { |
305 | 0 | const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
306 | 0 | unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type; |
307 | 0 | unsigned int number; |
308 | 0 | bool updated; |
309 | |
|
310 | 0 | if (bed->merge_gnu_properties != NULL |
311 | 0 | && pr_type >= GNU_PROPERTY_LOPROC |
312 | 0 | && pr_type < GNU_PROPERTY_LOUSER) |
313 | 0 | return bed->merge_gnu_properties (info, abfd, bbfd, aprop, bprop); |
314 | | |
315 | 0 | switch (pr_type) |
316 | 0 | { |
317 | 0 | case GNU_PROPERTY_STACK_SIZE: |
318 | 0 | if (aprop != NULL && bprop != NULL) |
319 | 0 | { |
320 | 0 | if (bprop->u.number > aprop->u.number) |
321 | 0 | { |
322 | 0 | aprop->u.number = bprop->u.number; |
323 | 0 | return true; |
324 | 0 | } |
325 | 0 | break; |
326 | 0 | } |
327 | | /* FALLTHROUGH */ |
328 | | |
329 | 0 | case GNU_PROPERTY_NO_COPY_ON_PROTECTED: |
330 | 0 | case GNU_PROPERTY_MEMORY_SEAL: |
331 | | /* Return TRUE if APROP is NULL to indicate that BPROP should |
332 | | be added to ABFD. */ |
333 | 0 | return aprop == NULL; |
334 | | |
335 | 0 | default: |
336 | 0 | updated = false; |
337 | 0 | if (pr_type >= GNU_PROPERTY_UINT32_OR_LO |
338 | 0 | && pr_type <= GNU_PROPERTY_UINT32_OR_HI) |
339 | 0 | { |
340 | 0 | if (aprop != NULL && bprop != NULL) |
341 | 0 | { |
342 | 0 | number = aprop->u.number; |
343 | 0 | aprop->u.number = number | bprop->u.number; |
344 | | /* Remove the property if all bits are empty. */ |
345 | 0 | if (aprop->u.number == 0) |
346 | 0 | { |
347 | 0 | aprop->pr_kind = property_remove; |
348 | 0 | updated = true; |
349 | 0 | } |
350 | 0 | else |
351 | 0 | updated = number != (unsigned int) aprop->u.number; |
352 | 0 | } |
353 | 0 | else |
354 | 0 | { |
355 | | /* Only one of APROP and BPROP can be NULL. */ |
356 | 0 | if (aprop != NULL) |
357 | 0 | { |
358 | 0 | if (aprop->u.number == 0) |
359 | 0 | { |
360 | | /* Remove APROP if all bits are empty. */ |
361 | 0 | aprop->pr_kind = property_remove; |
362 | 0 | updated = true; |
363 | 0 | } |
364 | 0 | } |
365 | 0 | else |
366 | 0 | { |
367 | | /* Return TRUE if APROP is NULL and all bits of BPROP |
368 | | aren't empty to indicate that BPROP should be added |
369 | | to ABFD. */ |
370 | 0 | updated = bprop->u.number != 0; |
371 | 0 | } |
372 | 0 | } |
373 | 0 | return updated; |
374 | 0 | } |
375 | 0 | else if (pr_type >= GNU_PROPERTY_UINT32_AND_LO |
376 | 0 | && pr_type <= GNU_PROPERTY_UINT32_AND_HI) |
377 | 0 | { |
378 | | /* Only one of APROP and BPROP can be NULL: |
379 | | 1. APROP & BPROP when both APROP and BPROP aren't NULL. |
380 | | 2. If APROP is NULL, remove x86 feature. |
381 | | 3. Otherwise, do nothing. |
382 | | */ |
383 | 0 | if (aprop != NULL && bprop != NULL) |
384 | 0 | { |
385 | 0 | number = aprop->u.number; |
386 | 0 | aprop->u.number = number & bprop->u.number; |
387 | 0 | updated = number != (unsigned int) aprop->u.number; |
388 | | /* Remove the property if all feature bits are cleared. */ |
389 | 0 | if (aprop->u.number == 0) |
390 | 0 | aprop->pr_kind = property_remove; |
391 | 0 | } |
392 | 0 | else |
393 | 0 | { |
394 | | /* There should be no AND properties since some input |
395 | | doesn't have them. */ |
396 | 0 | if (aprop != NULL) |
397 | 0 | { |
398 | 0 | aprop->pr_kind = property_remove; |
399 | 0 | updated = true; |
400 | 0 | } |
401 | 0 | } |
402 | 0 | return updated; |
403 | 0 | } |
404 | | |
405 | | /* Never should happen. */ |
406 | 0 | abort (); |
407 | 0 | } |
408 | | |
409 | 0 | return false; |
410 | 0 | } |
411 | | |
412 | | /* Return the property of TYPE on *LISTP and remove it from *LISTP if RM is |
413 | | true. Return NULL if not found. */ |
414 | | |
415 | | static elf_property * |
416 | | elf_find_and_remove_property (elf_property_list **listp, |
417 | | unsigned int type, bool rm) |
418 | 0 | { |
419 | 0 | elf_property_list *prev; |
420 | 0 | elf_property_list *p = _bfd_elf_find_property (*listp, type, &prev); |
421 | 0 | if (p == NULL) |
422 | 0 | return NULL; |
423 | | |
424 | 0 | if (rm) |
425 | 0 | *listp = _bfd_elf_remove_property (*listp, p, prev); |
426 | | |
427 | | /* FIXME: we leak memory with this approach. */ |
428 | 0 | return &p->property; |
429 | 0 | } |
430 | | |
431 | | /* Merge GNU property list *LISTP in ABFD with FIRST_PBFD. */ |
432 | | |
433 | | static void |
434 | | elf_merge_gnu_property_list (struct bfd_link_info *info, bfd *first_pbfd, |
435 | | bfd *abfd, elf_property_list **listp) |
436 | 0 | { |
437 | 0 | elf_property_list *p, **lastp; |
438 | 0 | elf_property *pr; |
439 | 0 | bool number_p; |
440 | 0 | bfd_vma number = 0; |
441 | | |
442 | | /* Merge each GNU property in FIRST_PBFD with the one on *LISTP. */ |
443 | 0 | lastp = &elf_properties (first_pbfd); |
444 | 0 | for (p = *lastp; p; p = p->next) |
445 | 0 | if (p->property.pr_kind != property_remove) |
446 | 0 | { |
447 | 0 | if (p->property.pr_kind == property_number) |
448 | 0 | { |
449 | 0 | number_p = true; |
450 | 0 | number = p->property.u.number; |
451 | 0 | } |
452 | 0 | else |
453 | 0 | number_p = false; |
454 | 0 | pr = elf_find_and_remove_property (listp, p->property.pr_type, |
455 | 0 | true); |
456 | | /* Pass NULL to elf_merge_gnu_properties for the property which |
457 | | isn't on *LISTP. */ |
458 | 0 | elf_merge_gnu_properties (info, first_pbfd, abfd, &p->property, pr); |
459 | 0 | if (p->property.pr_kind == property_remove) |
460 | 0 | { |
461 | 0 | if (info->has_map_file) |
462 | 0 | { |
463 | 0 | if (number_p) |
464 | 0 | { |
465 | 0 | if (pr != NULL) |
466 | 0 | info->callbacks->minfo |
467 | 0 | (_("Removed property %W to merge %pB (0x%v) " |
468 | 0 | "and %pB (0x%v)\n"), |
469 | 0 | (bfd_vma) p->property.pr_type, first_pbfd, |
470 | 0 | number, abfd, pr->u.number); |
471 | 0 | else |
472 | 0 | info->callbacks->minfo |
473 | 0 | (_("Removed property %W to merge %pB (0x%v) " |
474 | 0 | "and %pB (not found)\n"), |
475 | 0 | (bfd_vma) p->property.pr_type, first_pbfd, |
476 | 0 | number, abfd); |
477 | 0 | } |
478 | 0 | else |
479 | 0 | { |
480 | 0 | if (pr != NULL) |
481 | 0 | info->callbacks->minfo |
482 | 0 | (_("Removed property %W to merge %pB and %pB\n"), |
483 | 0 | (bfd_vma) p->property.pr_type, first_pbfd, abfd); |
484 | 0 | else |
485 | 0 | info->callbacks->minfo |
486 | 0 | (_("Removed property %W to merge %pB and %pB " |
487 | 0 | "(not found)\n"), |
488 | 0 | (bfd_vma) p->property.pr_type, first_pbfd, abfd); |
489 | 0 | } |
490 | 0 | } |
491 | | |
492 | | /* Remove this property. */ |
493 | 0 | *lastp = p->next; |
494 | 0 | continue; |
495 | 0 | } |
496 | 0 | else if (number_p) |
497 | 0 | { |
498 | 0 | if (pr != NULL) |
499 | 0 | { |
500 | 0 | if (p->property.u.number != number |
501 | 0 | || p->property.u.number != pr->u.number) |
502 | 0 | info->callbacks->minfo |
503 | 0 | (_("Updated property %W (0x%v) to merge %pB (0x%v) " |
504 | 0 | "and %pB (0x%v)\n"), |
505 | 0 | (bfd_vma) p->property.pr_type, p->property.u.number, |
506 | 0 | first_pbfd, number, abfd, pr->u.number); |
507 | 0 | } |
508 | 0 | else |
509 | 0 | { |
510 | 0 | if (p->property.u.number != number) |
511 | 0 | info->callbacks->minfo |
512 | 0 | (_("Updated property %W (%v) to merge %pB (0x%v) " |
513 | 0 | "and %pB (not found)\n"), |
514 | 0 | (bfd_vma) p->property.pr_type, p->property.u.number, |
515 | 0 | first_pbfd, number, abfd); |
516 | 0 | } |
517 | 0 | } |
518 | 0 | lastp = &p->next; |
519 | 0 | } |
520 | | |
521 | | /* Merge the remaining properties on *LISTP with FIRST_PBFD. */ |
522 | 0 | for (p = *listp; p != NULL; p = p->next) |
523 | 0 | { |
524 | 0 | if (p->property.pr_kind == property_number) |
525 | 0 | { |
526 | 0 | number_p = true; |
527 | 0 | number = p->property.u.number; |
528 | 0 | } |
529 | 0 | else |
530 | 0 | number_p = false; |
531 | |
|
532 | 0 | if (elf_merge_gnu_properties (info, first_pbfd, abfd, NULL, &p->property)) |
533 | 0 | { |
534 | 0 | if (p->property.pr_type == GNU_PROPERTY_NO_COPY_ON_PROTECTED) |
535 | 0 | elf_has_no_copy_on_protected (first_pbfd) = true; |
536 | |
|
537 | 0 | pr = _bfd_elf_get_property (first_pbfd, p->property.pr_type, |
538 | 0 | p->property.pr_datasz); |
539 | | /* It must be a new property. */ |
540 | 0 | if (pr->pr_kind != property_unknown) |
541 | 0 | abort (); |
542 | | /* Add a new property. */ |
543 | 0 | *pr = p->property; |
544 | 0 | } |
545 | 0 | else |
546 | 0 | { |
547 | 0 | pr = elf_find_and_remove_property (&elf_properties (first_pbfd), |
548 | 0 | p->property.pr_type, |
549 | 0 | false); |
550 | 0 | if (pr == NULL) |
551 | 0 | { |
552 | 0 | if (number_p) |
553 | 0 | info->callbacks->minfo |
554 | 0 | (_("Removed property %W to merge %pB (not found) and " |
555 | 0 | "%pB (0x%v)\n"), |
556 | 0 | (bfd_vma) p->property.pr_type, first_pbfd, abfd, |
557 | 0 | number); |
558 | 0 | else |
559 | 0 | info->callbacks->minfo |
560 | 0 | (_("Removed property %W to merge %pB and %pB\n"), |
561 | 0 | (bfd_vma) p->property.pr_type, first_pbfd, abfd); |
562 | 0 | } |
563 | 0 | else if (pr->pr_kind != property_remove) |
564 | 0 | abort (); |
565 | 0 | } |
566 | 0 | } |
567 | 0 | } |
568 | | |
569 | | /* Get GNU property section size. */ |
570 | | |
571 | | static bfd_size_type |
572 | | elf_get_gnu_property_section_size (elf_property_list *list, |
573 | | unsigned int align_size) |
574 | 0 | { |
575 | 0 | bfd_size_type size; |
576 | 0 | unsigned int descsz; |
577 | | |
578 | | /* Compute the output section size. */ |
579 | 0 | descsz = offsetof (Elf_External_Note, name[sizeof "GNU"]); |
580 | 0 | descsz = (descsz + 3) & -(unsigned int) 4; |
581 | 0 | size = descsz; |
582 | 0 | for (; list != NULL; list = list->next) |
583 | 0 | { |
584 | 0 | unsigned int datasz; |
585 | | /* Check if this property should be skipped. */ |
586 | 0 | if (list->property.pr_kind == property_remove) |
587 | 0 | continue; |
588 | | /* There are 4 byte type + 4 byte datasz for each property. */ |
589 | 0 | if (list->property.pr_type == GNU_PROPERTY_STACK_SIZE) |
590 | 0 | datasz = align_size; |
591 | 0 | else |
592 | 0 | datasz = list->property.pr_datasz; |
593 | 0 | size += 4 + 4 + datasz; |
594 | | /* Align each property. */ |
595 | 0 | size = (size + (align_size - 1)) & ~(align_size - 1); |
596 | 0 | } |
597 | |
|
598 | 0 | return size; |
599 | 0 | } |
600 | | |
601 | | /* Write GNU properties. */ |
602 | | |
603 | | static void |
604 | | elf_write_gnu_properties (struct bfd_link_info *info, |
605 | | bfd *abfd, bfd_byte *contents, |
606 | | elf_property_list *list, unsigned int size, |
607 | | unsigned int align_size) |
608 | 0 | { |
609 | 0 | unsigned int descsz; |
610 | 0 | unsigned int datasz; |
611 | 0 | Elf_External_Note *e_note; |
612 | |
|
613 | 0 | e_note = (Elf_External_Note *) contents; |
614 | 0 | descsz = offsetof (Elf_External_Note, name[sizeof "GNU"]); |
615 | 0 | descsz = (descsz + 3) & -(unsigned int) 4; |
616 | 0 | bfd_h_put_32 (abfd, sizeof "GNU", &e_note->namesz); |
617 | 0 | bfd_h_put_32 (abfd, size - descsz, &e_note->descsz); |
618 | 0 | bfd_h_put_32 (abfd, NT_GNU_PROPERTY_TYPE_0, &e_note->type); |
619 | 0 | memcpy (e_note->name, "GNU", sizeof "GNU"); |
620 | |
|
621 | 0 | size = descsz; |
622 | 0 | for (; list != NULL; list = list->next) |
623 | 0 | { |
624 | | /* Check if this property should be skipped. */ |
625 | 0 | if (list->property.pr_kind == property_remove) |
626 | 0 | continue; |
627 | | /* There are 4 byte type + 4 byte datasz for each property. */ |
628 | 0 | if (list->property.pr_type == GNU_PROPERTY_STACK_SIZE) |
629 | 0 | datasz = align_size; |
630 | 0 | else |
631 | 0 | datasz = list->property.pr_datasz; |
632 | 0 | bfd_h_put_32 (abfd, list->property.pr_type, contents + size); |
633 | 0 | bfd_h_put_32 (abfd, datasz, contents + size + 4); |
634 | 0 | size += 4 + 4; |
635 | | |
636 | | /* Write out property value. */ |
637 | 0 | switch (list->property.pr_kind) |
638 | 0 | { |
639 | 0 | case property_number: |
640 | 0 | switch (datasz) |
641 | 0 | { |
642 | 0 | default: |
643 | | /* Never should happen. */ |
644 | 0 | abort (); |
645 | | |
646 | 0 | case 0: |
647 | 0 | break; |
648 | | |
649 | 0 | case 4: |
650 | | /* Save the pointer to GNU_PROPERTY_1_NEEDED so that it |
651 | | can be updated later if needed. */ |
652 | 0 | if (info != NULL |
653 | 0 | && list->property.pr_type == GNU_PROPERTY_1_NEEDED) |
654 | 0 | info->needed_1_p = contents + size; |
655 | 0 | bfd_h_put_32 (abfd, list->property.u.number, |
656 | 0 | contents + size); |
657 | 0 | break; |
658 | | |
659 | 0 | case 8: |
660 | 0 | bfd_h_put_64 (abfd, list->property.u.number, |
661 | 0 | contents + size); |
662 | 0 | break; |
663 | 0 | } |
664 | 0 | break; |
665 | | |
666 | 0 | default: |
667 | | /* Never should happen. */ |
668 | 0 | abort (); |
669 | 0 | } |
670 | 0 | size += datasz; |
671 | | |
672 | | /* Align each property. */ |
673 | 0 | size = (size + (align_size - 1)) & ~ (align_size - 1); |
674 | 0 | } |
675 | 0 | } |
676 | | |
677 | | static asection * |
678 | | _bfd_elf_link_create_gnu_property_sec (struct bfd_link_info *info, bfd *elf_bfd, |
679 | | unsigned int elfclass) |
680 | 0 | { |
681 | 0 | asection *sec; |
682 | |
|
683 | 0 | sec = bfd_make_section_with_flags (elf_bfd, |
684 | 0 | NOTE_GNU_PROPERTY_SECTION_NAME, |
685 | 0 | (SEC_ALLOC |
686 | 0 | | SEC_LOAD |
687 | 0 | | SEC_IN_MEMORY |
688 | 0 | | SEC_READONLY |
689 | 0 | | SEC_HAS_CONTENTS |
690 | 0 | | SEC_DATA)); |
691 | 0 | if (sec == NULL |
692 | 0 | || !bfd_set_section_alignment (sec, elfclass == ELFCLASS64 ? 3 : 2)) |
693 | 0 | info->callbacks->fatal (_("%P: failed to create %s\n"), |
694 | 0 | NOTE_GNU_PROPERTY_SECTION_NAME); |
695 | | |
696 | 0 | elf_section_type (sec) = SHT_NOTE; |
697 | 0 | return sec; |
698 | 0 | } |
699 | | |
700 | | |
701 | | /* Set up GNU properties. Return the first relocatable ELF input with |
702 | | GNU properties if found. Otherwise, return NULL. */ |
703 | | |
704 | | bfd * |
705 | | _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info) |
706 | 0 | { |
707 | 0 | bfd *abfd, *first_pbfd = NULL, *elf_bfd = NULL; |
708 | 0 | elf_property_list *list; |
709 | 0 | asection *sec; |
710 | 0 | bool has_properties = false; |
711 | 0 | const struct elf_backend_data *bed |
712 | 0 | = get_elf_backend_data (info->output_bfd); |
713 | 0 | unsigned int elfclass = bed->s->elfclass; |
714 | 0 | int elf_machine_code = bed->elf_machine_code; |
715 | 0 | elf_property *p; |
716 | | |
717 | | /* Find the first relocatable ELF input with GNU properties. */ |
718 | 0 | for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) |
719 | 0 | if (bfd_get_flavour (abfd) == bfd_target_elf_flavour |
720 | 0 | && (abfd->flags & DYNAMIC) == 0 |
721 | 0 | && (elf_machine_code |
722 | 0 | == get_elf_backend_data (abfd)->elf_machine_code) |
723 | 0 | && (elfclass == get_elf_backend_data (abfd)->s->elfclass)) |
724 | 0 | { |
725 | | /* Ignore GNU properties from ELF objects with different machine |
726 | | code or class. Also skip objects without a GNU_PROPERTY note |
727 | | section. */ |
728 | 0 | elf_bfd = abfd; |
729 | |
|
730 | 0 | if (elf_properties (abfd) != NULL) |
731 | 0 | { |
732 | 0 | has_properties = true; |
733 | |
|
734 | 0 | if (bfd_get_section_by_name (abfd, |
735 | 0 | NOTE_GNU_PROPERTY_SECTION_NAME) |
736 | 0 | != NULL) |
737 | 0 | { |
738 | | /* Keep .note.gnu.property section in FIRST_PBFD. */ |
739 | 0 | first_pbfd = abfd; |
740 | 0 | break; |
741 | 0 | } |
742 | 0 | } |
743 | 0 | } |
744 | |
|
745 | 0 | if (info->indirect_extern_access > 0 && elf_bfd != NULL) |
746 | 0 | { |
747 | | /* Support -z indirect-extern-access. */ |
748 | 0 | if (first_pbfd == NULL) |
749 | 0 | { |
750 | 0 | sec = _bfd_elf_link_create_gnu_property_sec (info, elf_bfd, elfclass); |
751 | 0 | first_pbfd = elf_bfd; |
752 | 0 | has_properties = true; |
753 | 0 | } |
754 | |
|
755 | 0 | p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_1_NEEDED, 4); |
756 | 0 | if (p->pr_kind == property_unknown) |
757 | 0 | { |
758 | | /* Create GNU_PROPERTY_1_NEEDED. */ |
759 | 0 | p->u.number |
760 | 0 | = GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS; |
761 | 0 | p->pr_kind = property_number; |
762 | 0 | } |
763 | 0 | else |
764 | 0 | p->u.number |
765 | 0 | |= GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS; |
766 | 0 | } |
767 | |
|
768 | 0 | if (elf_bfd != NULL) |
769 | 0 | { |
770 | 0 | if (info->memory_seal) |
771 | 0 | { |
772 | | /* Support -z no-memory-seal. */ |
773 | 0 | if (first_pbfd == NULL) |
774 | 0 | { |
775 | 0 | sec = _bfd_elf_link_create_gnu_property_sec (info, elf_bfd, elfclass); |
776 | 0 | first_pbfd = elf_bfd; |
777 | 0 | has_properties = true; |
778 | 0 | } |
779 | |
|
780 | 0 | p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_MEMORY_SEAL, 0); |
781 | 0 | if (p->pr_kind == property_unknown) |
782 | 0 | { |
783 | | /* Create GNU_PROPERTY_NO_MEMORY_SEAL. */ |
784 | 0 | p->u.number = GNU_PROPERTY_MEMORY_SEAL; |
785 | 0 | p->pr_kind = property_number; |
786 | 0 | } |
787 | 0 | } |
788 | 0 | else |
789 | 0 | elf_find_and_remove_property (&elf_properties (elf_bfd), |
790 | 0 | GNU_PROPERTY_MEMORY_SEAL, true); |
791 | 0 | } |
792 | | |
793 | | /* Do nothing if there is no .note.gnu.property section. */ |
794 | 0 | if (!has_properties) |
795 | 0 | return NULL; |
796 | | |
797 | | /* Merge .note.gnu.property sections. */ |
798 | 0 | info->callbacks->minfo (_("\n")); |
799 | 0 | info->callbacks->minfo (_("Merging program properties\n")); |
800 | 0 | info->callbacks->minfo (_("\n")); |
801 | |
|
802 | 0 | for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) |
803 | 0 | if (abfd != first_pbfd |
804 | 0 | && (abfd->flags & (DYNAMIC | BFD_PLUGIN | BFD_LINKER_CREATED)) == 0) |
805 | 0 | { |
806 | 0 | elf_property_list *null_ptr = NULL; |
807 | 0 | elf_property_list **listp = &null_ptr; |
808 | | |
809 | | /* Merge .note.gnu.property section in relocatable ELF input. */ |
810 | 0 | if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) |
811 | 0 | { |
812 | 0 | list = elf_properties (abfd); |
813 | | |
814 | | /* Ignore GNU properties from ELF objects with different |
815 | | machine code. */ |
816 | 0 | if (list != NULL |
817 | 0 | && (elf_machine_code |
818 | 0 | == get_elf_backend_data (abfd)->elf_machine_code)) |
819 | 0 | listp = &elf_properties (abfd); |
820 | 0 | } |
821 | 0 | else |
822 | 0 | list = NULL; |
823 | | |
824 | | /* Merge properties with FIRST_PBFD. FIRST_PBFD can be NULL |
825 | | when all properties are from ELF objects with different |
826 | | machine code or class. */ |
827 | 0 | if (first_pbfd != NULL) |
828 | 0 | elf_merge_gnu_property_list (info, first_pbfd, abfd, listp); |
829 | |
|
830 | 0 | if (list != NULL) |
831 | 0 | { |
832 | | /* Discard the .note.gnu.property section in this bfd. */ |
833 | 0 | sec = bfd_get_section_by_name (abfd, |
834 | 0 | NOTE_GNU_PROPERTY_SECTION_NAME); |
835 | 0 | if (sec != NULL) |
836 | 0 | sec->output_section = bfd_abs_section_ptr; |
837 | 0 | } |
838 | 0 | } |
839 | | |
840 | | /* Rewrite .note.gnu.property section so that GNU properties are |
841 | | always sorted by type even if input GNU properties aren't sorted. */ |
842 | 0 | if (first_pbfd != NULL) |
843 | 0 | { |
844 | 0 | bfd_size_type size; |
845 | 0 | bfd_byte *contents; |
846 | 0 | unsigned int align_size = elfclass == ELFCLASS64 ? 8 : 4; |
847 | |
|
848 | 0 | sec = bfd_get_section_by_name (first_pbfd, |
849 | 0 | NOTE_GNU_PROPERTY_SECTION_NAME); |
850 | 0 | BFD_ASSERT (sec != NULL); |
851 | | |
852 | | /* Update stack size in .note.gnu.property with -z stack-size=N |
853 | | if N > 0. */ |
854 | 0 | if (info->stacksize > 0) |
855 | 0 | { |
856 | 0 | bfd_vma stacksize = info->stacksize; |
857 | |
|
858 | 0 | p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_STACK_SIZE, |
859 | 0 | align_size); |
860 | 0 | if (p->pr_kind == property_unknown) |
861 | 0 | { |
862 | | /* Create GNU_PROPERTY_STACK_SIZE. */ |
863 | 0 | p->u.number = stacksize; |
864 | 0 | p->pr_kind = property_number; |
865 | 0 | } |
866 | 0 | else if (stacksize > p->u.number) |
867 | 0 | p->u.number = stacksize; |
868 | 0 | } |
869 | 0 | else if (elf_properties (first_pbfd) == NULL) |
870 | 0 | { |
871 | | /* Discard .note.gnu.property section if all properties have |
872 | | been removed. */ |
873 | 0 | sec->output_section = bfd_abs_section_ptr; |
874 | 0 | return NULL; |
875 | 0 | } |
876 | | |
877 | | /* Fix up GNU properties. */ |
878 | 0 | if (bed->fixup_gnu_properties) |
879 | 0 | bed->fixup_gnu_properties (info, &elf_properties (first_pbfd)); |
880 | |
|
881 | 0 | if (elf_properties (first_pbfd) == NULL) |
882 | 0 | { |
883 | | /* Discard .note.gnu.property section if all properties have |
884 | | been removed. */ |
885 | 0 | sec->output_section = bfd_abs_section_ptr; |
886 | 0 | return NULL; |
887 | 0 | } |
888 | | |
889 | | /* Compute the section size. */ |
890 | 0 | list = elf_properties (first_pbfd); |
891 | 0 | size = elf_get_gnu_property_section_size (list, align_size); |
892 | | |
893 | | /* Update .note.gnu.property section now. */ |
894 | 0 | sec->size = size; |
895 | 0 | contents = (bfd_byte *) bfd_zalloc (first_pbfd, size); |
896 | |
|
897 | 0 | if (info->indirect_extern_access <= 0) |
898 | 0 | { |
899 | | /* Get GNU_PROPERTY_1_NEEDED properties. */ |
900 | 0 | p = elf_find_and_remove_property (&elf_properties (first_pbfd), |
901 | 0 | GNU_PROPERTY_1_NEEDED, false); |
902 | 0 | if (p != NULL) |
903 | 0 | { |
904 | 0 | if (info->indirect_extern_access < 0) |
905 | 0 | { |
906 | | /* Set indirect_extern_access to 1 to indicate that |
907 | | it is turned on by input properties. */ |
908 | 0 | if ((p->u.number |
909 | 0 | & GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS) |
910 | 0 | != 0) |
911 | 0 | info->indirect_extern_access = 1; |
912 | 0 | } |
913 | 0 | else |
914 | | /* Turn off indirect external access. */ |
915 | 0 | p->u.number |
916 | 0 | &= ~GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS; |
917 | 0 | } |
918 | 0 | } |
919 | |
|
920 | 0 | elf_write_gnu_properties (info, first_pbfd, contents, list, size, |
921 | 0 | align_size); |
922 | | |
923 | | /* Cache the section contents for elf_link_input_bfd. */ |
924 | 0 | sec->alloced = 1; |
925 | 0 | elf_section_data (sec)->this_hdr.contents = contents; |
926 | | |
927 | | /* If GNU_PROPERTY_NO_COPY_ON_PROTECTED is set, protected data |
928 | | symbol is defined in the shared object. */ |
929 | 0 | if (elf_has_no_copy_on_protected (first_pbfd)) |
930 | 0 | info->extern_protected_data = false; |
931 | |
|
932 | 0 | if (info->indirect_extern_access > 0) |
933 | 0 | { |
934 | | /* For indirect external access, don't generate copy |
935 | | relocations. NB: Set to nocopyreloc to 2 to indicate |
936 | | that it is implied by indirect_extern_access. */ |
937 | 0 | info->nocopyreloc = 2; |
938 | 0 | info->extern_protected_data = false; |
939 | 0 | } |
940 | 0 | } |
941 | | |
942 | 0 | return first_pbfd; |
943 | 0 | } |
944 | | |
945 | | /* Convert GNU property size. */ |
946 | | |
947 | | bfd_size_type |
948 | | _bfd_elf_convert_gnu_property_size (bfd *ibfd, bfd *obfd) |
949 | 0 | { |
950 | 0 | unsigned int align_size; |
951 | 0 | const struct elf_backend_data *bed; |
952 | 0 | elf_property_list *list = elf_properties (ibfd); |
953 | |
|
954 | 0 | bed = get_elf_backend_data (obfd); |
955 | 0 | align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4; |
956 | | |
957 | | /* Get the output .note.gnu.property section size. */ |
958 | 0 | return elf_get_gnu_property_section_size (list, align_size); |
959 | 0 | } |
960 | | |
961 | | /* Convert GNU properties. */ |
962 | | |
963 | | bool |
964 | | _bfd_elf_convert_gnu_properties (bfd *ibfd, asection *isec, |
965 | | bfd *obfd, bfd_byte **ptr, |
966 | | bfd_size_type *ptr_size) |
967 | 0 | { |
968 | 0 | unsigned int size; |
969 | 0 | bfd_byte *contents; |
970 | 0 | unsigned int align_shift; |
971 | 0 | const struct elf_backend_data *bed; |
972 | 0 | elf_property_list *list = elf_properties (ibfd); |
973 | |
|
974 | 0 | bed = get_elf_backend_data (obfd); |
975 | 0 | align_shift = bed->s->elfclass == ELFCLASS64 ? 3 : 2; |
976 | | |
977 | | /* Get the output .note.gnu.property section size. */ |
978 | 0 | size = bfd_section_size (isec->output_section); |
979 | | |
980 | | /* Update the output .note.gnu.property section alignment. */ |
981 | 0 | bfd_set_section_alignment (isec->output_section, align_shift); |
982 | |
|
983 | 0 | if (size > bfd_section_size (isec)) |
984 | 0 | { |
985 | 0 | contents = (bfd_byte *) bfd_malloc (size); |
986 | 0 | if (contents == NULL) |
987 | 0 | return false; |
988 | 0 | free (*ptr); |
989 | 0 | *ptr = contents; |
990 | 0 | } |
991 | 0 | else |
992 | 0 | contents = *ptr; |
993 | | |
994 | 0 | *ptr_size = size; |
995 | | |
996 | | /* Generate the output .note.gnu.property section. */ |
997 | 0 | elf_write_gnu_properties (NULL, ibfd, contents, list, size, |
998 | 0 | 1 << align_shift); |
999 | |
|
1000 | 0 | return true; |
1001 | 0 | } |