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