1 /* ELF program property support.
2 Copyright (C) 2017 Free Software Foundation, Inc.
4 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
21 /* GNU program property draft is at:
23 https://github.com/hjl-tools/linux-abi/wiki/property-draft.pdf
31 /* Get a property, allocate a new one if needed. */
34 _bfd_elf_get_property (bfd *abfd, unsigned int type, unsigned int datasz)
36 elf_property_list *p, **lastp;
38 if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
40 /* Never should happen. */
44 /* Keep the property list in order of type. */
45 lastp = &elf_properties (abfd);
46 for (p = *lastp; p; p = p->next)
48 /* Reuse the existing entry. */
49 if (type == p->property.pr_type)
51 if (datasz > p->property.pr_datasz)
53 /* This can happen when mixing 32-bit and 64-bit objects. */
54 p->property.pr_datasz = datasz;
58 else if (type < p->property.pr_type)
62 p = (elf_property_list *) bfd_alloc (abfd, sizeof (*p));
65 _bfd_error_handler (_("%B: out of memory in _bfd_elf_get_property"),
69 memset (p, 0, sizeof (*p));
70 p->property.pr_type = type;
71 p->property.pr_datasz = datasz;
72 p->property.filename = abfd->filename;
78 /* Parse GNU properties. */
81 _bfd_elf_parse_gnu_properties (bfd *abfd, Elf_Internal_Note *note)
83 const struct elf_backend_data *bed = get_elf_backend_data (abfd);
84 unsigned int align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4;
85 bfd_byte *ptr = (bfd_byte *) note->descdata;
86 bfd_byte *ptr_end = ptr + note->descsz;
88 if (note->descsz < 8 || (note->descsz % align_size) != 0)
92 (_("warning: %B: corrupt GNU_PROPERTY_TYPE (%ld) size: %#lx\n"),
93 abfd, note->type, note->descsz);
99 unsigned int type = bfd_h_get_32 (abfd, ptr);
100 unsigned int datasz = bfd_h_get_32 (abfd, ptr + 4);
105 if ((ptr + datasz) > ptr_end)
108 (_("warning: %B: corrupt GNU_PROPERTY_TYPE (%ld) type (0x%x) datasz: 0x%x\n"),
109 abfd, note->type, type, datasz);
110 /* Clear all properties. */
111 elf_properties (abfd) = NULL;
115 if (type >= GNU_PROPERTY_LOPROC)
117 if (type < GNU_PROPERTY_LOUSER && bed->parse_gnu_properties)
119 enum elf_property_kind kind
120 = bed->parse_gnu_properties (abfd, type, ptr, datasz);
121 if (kind == property_corrupt)
123 /* Clear all properties. */
124 elf_properties (abfd) = NULL;
127 else if (kind != property_ignored)
135 case GNU_PROPERTY_STACK_SIZE:
136 if (datasz != align_size)
139 (_("warning: %B: corrupt stack size: 0x%x\n"),
141 /* Clear all properties. */
142 elf_properties (abfd) = NULL;
145 prop = _bfd_elf_get_property (abfd, type, datasz);
147 prop->u.number = bfd_h_get_64 (abfd, ptr);
149 prop->u.number = bfd_h_get_32 (abfd, ptr);
150 prop->pr_kind = property_number;
153 case GNU_PROPERTY_NO_COPY_ON_PROTECTED:
157 (_("warning: %B: corrupt no copy on protected size: 0x%x\n"),
159 /* Clear all properties. */
160 elf_properties (abfd) = NULL;
163 prop = _bfd_elf_get_property (abfd, type, datasz);
164 prop->pr_kind = property_number;
167 case GNU_PROPERTY_COMPILER_FLAGS:
168 /* Note that annobin uses 4-byte alignment even on 64-bit targets. */
169 if (!((datasz == 4) || (datasz == 8)))
172 (_("warning: %B: corrupt compiler flags: 0x%x\n"),
174 /* Clear all properties. */
175 elf_properties (abfd) = NULL;
178 prop = _bfd_elf_get_property (abfd, type, datasz);
180 prop->u.number = bfd_h_get_64 (abfd, ptr);
182 prop->u.number = bfd_h_get_32 (abfd, ptr);
184 prop->pr_kind = property_number;
193 (_("warning: %B: unsupported GNU_PROPERTY_TYPE (%ld) type: 0x%x\n"),
194 abfd, note->type, type);
197 ptr += (datasz + (align_size - 1)) & ~ (align_size - 1);
201 if (ptr > (ptr_end - 8))
208 /* If validation bits are set - compare bit flags for equality. */
209 inline static bfd_boolean
210 elf_gnu_property_validate_flag (bfd_vma anum,
212 bfd_vma validation_bit_flag,
213 bfd_vma validation_bit)
215 if ((anum & validation_bit_flag) && (bnum & validation_bit_flag)
216 && ((anum & validation_bit) != (bnum & validation_bit)))
224 elf_validate_compiler_flags_properties (elf_property *aprop,
227 bfd_boolean is_flag_set;
229 /* Sanity check to verify correct usage. */
233 if (aprop->pr_type != bprop->pr_type)
236 BFD_ASSERT(aprop->pr_type == GNU_PROPERTY_COMPILER_FLAGS);
238 /* Return TRUE if compiler flags are identical (likely?). */
239 if (aprop->u.number == bprop->u.number)
242 if (!elf_gnu_property_validate_flag(aprop->u.number,
244 GNU_PROPERTY_SANITIZE_VALIDATION,
245 GNU_PROPERTY_SANITIZE_ADDRESS))
247 is_flag_set = bprop->u.number & GNU_PROPERTY_SANITIZE_ADDRESS;
249 (_("%s: ERROR: Validation failed, linking %s object with previous %s"),
250 bprop->filename, is_flag_set ? "sanitized" : "unsanitized",
251 !is_flag_set ? "sanitized" : "unsanitized");
255 if (!elf_gnu_property_validate_flag(aprop->u.number,
257 GNU_PROPERTY_USECXX_VALIDATION,
258 GNU_PROPERTY_USECXX11_ABI))
260 is_flag_set = bprop->u.number & GNU_PROPERTY_USECXX11_ABI;
262 (_("ERROR: Validation failed, linking %s ABI object with %s ABI"),
263 bprop->filename, is_flag_set ? "pre-cxx11" : "cxx11",
264 !is_flag_set ? "pre-cxx11" : "cxx11");
272 /* Merge bprop into aprop according compiler-flags properties, return TRUE if */
273 /* aprop is updated. */
275 elf_merge_gnu_properties_compiler_flags (elf_property *aprop,
278 bfd_boolean is_updated = FALSE;
279 /* Likely that objects have the same properties. */
280 if (aprop->u.number == bprop->u.number) {
284 /* Validation bit + no-validation bit = validation bit. */
285 if ((aprop->u.number ^ bprop->u.number) & GNU_PROPERTY_SANITIZE_VALIDATION)
287 aprop->u.number |= GNU_PROPERTY_SANITIZE_VALIDATION;
290 /* Sanitized object + unsanitized results = sanitized final object. */
291 if ((aprop->u.number ^ bprop->u.number) & GNU_PROPERTY_SANITIZE_ADDRESS)
293 aprop->u.number |= GNU_PROPERTY_SANITIZE_ADDRESS;
297 if ((aprop->u.number ^ bprop->u.number) & GNU_PROPERTY_USECXX_VALIDATION)
299 aprop->u.number |= GNU_PROPERTY_USECXX_VALIDATION;
303 if ((aprop->u.number ^ bprop->u.number) & GNU_PROPERTY_USECXX11_ABI)
305 aprop->u.number |= GNU_PROPERTY_USECXX11_ABI;
312 /* Merge GNU property BPROP with APROP. If APROP isn't NULL, return TRUE
313 if APROP is updated. Otherwise, return TRUE if BPROP should be merged
317 elf_merge_gnu_properties (bfd *abfd, elf_property *aprop,
320 const struct elf_backend_data *bed = get_elf_backend_data (abfd);
321 unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type;
323 if (bed->merge_gnu_properties != NULL
324 && pr_type >= GNU_PROPERTY_LOPROC
325 && pr_type < GNU_PROPERTY_LOUSER)
326 return bed->merge_gnu_properties (abfd, aprop, bprop);
330 case GNU_PROPERTY_STACK_SIZE:
331 if (aprop != NULL && bprop != NULL)
333 if (bprop->u.number > aprop->u.number)
335 aprop->u.number = bprop->u.number;
342 case GNU_PROPERTY_NO_COPY_ON_PROTECTED:
343 /* Return TRUE if APROP is NULL to indicate that BPROP should
345 return aprop == NULL;
348 case GNU_PROPERTY_COMPILER_FLAGS:
350 bfd_boolean is_updated;
351 if (aprop != NULL && bprop != NULL)
353 #ifdef ENABLE_ANNOBIN_VERIFICATION
354 if (!elf_validate_compiler_flags_properties (aprop, bprop))
356 _bfd_error_handler(_("ERROR: Linking failed due to incompatible "
357 "compilation flags used to generate objects\n"));
358 /* Strict mode, abort. */
359 #ifdef ENABLE_ANNOBIN_VERIFICATION_STRICT
360 _exit (EXIT_FAILURE);
364 is_updated = elf_merge_gnu_properties_compiler_flags (aprop, bprop);
369 /* aprop or bprop is NULL, warn for missing GNU_PROPERTY_COMPILER_FLAGS.
371 This is too noisy since glibc's crt{i,n}.o are compiled with
372 predefined flags (without annobin support), so we'll have at
373 least 2x of the following warning for every linking. May be
374 enabled after we verified crt* compilation with plugins. */
375 /* if (bprop == NULL)
377 (_("WARNING: not found (generated by annobin gcc plugin), "
378 "runtime verification may be incomplete"),
379 NOTE_GNU_PROPERTY_SECTION_NAME); */
386 /* Never should happen. */
393 /* Return the property of TYPE on *LISTP and remove it from *LISTP.
394 Return NULL if not found. */
396 static elf_property *
397 elf_find_and_remove_property (elf_property_list **listp,
400 elf_property_list *list;
402 for (list = *listp; list; list = list->next)
404 if (type == list->property.pr_type)
406 /* Remove this property. */
408 return &list->property;
410 else if (type < list->property.pr_type)
418 /* Merge GNU property list *LISTP with ABFD. */
421 elf_merge_gnu_property_list (bfd *abfd, elf_property_list **listp)
423 elf_property_list *p, **lastp;
426 /* Merge each GNU property in ABFD with the one on *LISTP. */
427 lastp = &elf_properties (abfd);
428 for (p = *lastp; p; p = p->next)
430 pr = elf_find_and_remove_property (listp, p->property.pr_type);
431 /* Pass NULL to elf_merge_gnu_properties for the property which
433 elf_merge_gnu_properties (abfd, &p->property, pr);
434 if (p->property.pr_kind == property_remove)
436 /* Remove this property. */
443 /* Merge the remaining properties on *LISTP with ABFD. */
444 for (p = *listp; p != NULL; p = p->next)
445 if (elf_merge_gnu_properties (abfd, NULL, &p->property))
447 pr = _bfd_elf_get_property (abfd, p->property.pr_type,
448 p->property.pr_datasz);
449 /* It must be a new property. */
450 if (pr->pr_kind != property_unknown)
452 /* Add a new property. */
457 /* Set up GNU properties. */
460 _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
462 bfd *abfd, *first_pbfd = NULL;
463 elf_property_list *list;
465 bfd_boolean has_properties = FALSE;
466 const struct elf_backend_data *bed
467 = get_elf_backend_data (info->output_bfd);
468 unsigned int elfclass = bed->s->elfclass;
469 int elf_machine_code = bed->elf_machine_code;
471 /* Find the first relocatable ELF input with GNU properties. */
472 for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
473 if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
474 && bfd_count_sections (abfd) != 0
475 && elf_properties (abfd) != NULL)
477 has_properties = TRUE;
479 /* Ignore GNU properties from ELF objects with different machine
481 if ((elf_machine_code
482 == get_elf_backend_data (abfd)->elf_machine_code)
484 == get_elf_backend_data (abfd)->s->elfclass))
486 /* Keep .note.gnu.property section in FIRST_PBFD. */
492 /* Do nothing if there is no .note.gnu.property section. */
496 /* Merge .note.gnu.property sections. */
497 for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
498 if (abfd != first_pbfd && bfd_count_sections (abfd) != 0)
500 elf_property_list *null_ptr = NULL;
501 elf_property_list **listp = &null_ptr;
503 /* Merge .note.gnu.property section in relocatable ELF input. */
504 if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
506 list = elf_properties (abfd);
508 /* Ignore GNU properties from ELF objects with different
512 == get_elf_backend_data (abfd)->elf_machine_code))
513 listp = &elf_properties (abfd);
518 /* Merge properties with FIRST_PBFD. FIRST_PBFD can be NULL
519 when all properties are from ELF objects with different
520 machine code or class. */
521 if (first_pbfd != NULL)
522 elf_merge_gnu_property_list (first_pbfd, listp);
526 /* Discard .note.gnu.property section in the rest inputs. */
527 sec = bfd_get_section_by_name (abfd,
528 NOTE_GNU_PROPERTY_SECTION_NAME);
529 sec->output_section = bfd_abs_section_ptr;
533 /* Rewrite .note.gnu.property section so that GNU properties are
534 always sorted by type even if input GNU properties aren't sorted. */
535 if (first_pbfd != NULL)
540 Elf_External_Note *e_note;
541 unsigned int align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4;
543 sec = bfd_get_section_by_name (first_pbfd,
544 NOTE_GNU_PROPERTY_SECTION_NAME);
549 /* Update stack size in .note.gnu.property with -z stack-size=N
551 if (info->stacksize > 0)
554 bfd_vma stacksize = info->stacksize;
556 p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_STACK_SIZE,
558 if (p->pr_kind == property_unknown)
560 /* Create GNU_PROPERTY_STACK_SIZE. */
561 p->u.number = stacksize;
562 p->pr_kind = property_number;
564 else if (stacksize > p->u.number)
565 p->u.number = stacksize;
567 else if (elf_properties (first_pbfd) == NULL)
569 /* Discard .note.gnu.property section if all properties have
571 sec->output_section = bfd_abs_section_ptr;
575 /* Compute the section size. */
576 descsz = offsetof (Elf_External_Note, name[sizeof "GNU"]);
577 descsz = (descsz + 3) & -(unsigned int) 4;
579 for (list = elf_properties (first_pbfd);
583 /* There are 4 byte type + 4 byte datasz for each property. */
584 size += 4 + 4 + list->property.pr_datasz;
585 /* Align each property. */
586 size = (size + (align_size - 1)) & ~(align_size - 1);
589 /* Update .note.gnu.property section now. */
591 contents = (bfd_byte *) bfd_zalloc (first_pbfd, size);
593 e_note = (Elf_External_Note *) contents;
594 bfd_h_put_32 (first_pbfd, sizeof "GNU", &e_note->namesz);
595 bfd_h_put_32 (first_pbfd, size - descsz, &e_note->descsz);
596 bfd_h_put_32 (first_pbfd, NT_GNU_PROPERTY_TYPE_0, &e_note->type);
597 memcpy (e_note->name, "GNU", sizeof "GNU");
600 for (list = elf_properties (first_pbfd);
604 /* There are 4 byte type + 4 byte datasz for each property. */
605 bfd_h_put_32 (first_pbfd, list->property.pr_type,
607 bfd_h_put_32 (first_pbfd, list->property.pr_datasz,
608 contents + size + 4);
611 /* Write out property value. */
612 switch (list->property.pr_kind)
614 case property_number:
615 switch (list->property.pr_datasz)
618 /* Never should happen. */
625 bfd_h_put_32 (first_pbfd, list->property.u.number,
630 bfd_h_put_64 (first_pbfd, list->property.u.number,
637 /* Never should happen. */
640 size += list->property.pr_datasz;
642 /* Align each property. */
643 size = (size + (align_size - 1)) & ~ (align_size - 1);
646 /* Cache the section contents for elf_link_input_bfd. */
647 elf_section_data (sec)->this_hdr.contents = contents;