/* ELF program property support.
- Copyright (C) 2017-2018 Free Software Foundation, Inc.
+ Copyright (C) 2017-2021 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
/* Parse GNU properties. */
-bfd_boolean
+bool
_bfd_elf_parse_gnu_properties (bfd *abfd, Elf_Internal_Note *note)
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
if (note->descsz < 8 || (note->descsz % align_size) != 0)
{
-bad_size:
+ bad_size:
_bfd_error_handler
(_("warning: %pB: corrupt GNU_PROPERTY_TYPE (%ld) size: %#lx"),
abfd, note->type, note->descsz);
- return FALSE;
+ return false;
}
while (ptr != ptr_end)
abfd, note->type, type, datasz);
/* Clear all properties. */
elf_properties (abfd) = NULL;
- return FALSE;
+ return false;
}
if (type >= GNU_PROPERTY_LOPROC)
{
/* Clear all properties. */
elf_properties (abfd) = NULL;
- return FALSE;
+ return false;
}
else if (kind != property_ignored)
goto next;
abfd, datasz);
/* Clear all properties. */
elf_properties (abfd) = NULL;
- return FALSE;
+ return false;
}
prop = _bfd_elf_get_property (abfd, type, datasz);
if (datasz == 8)
abfd, datasz);
/* Clear all properties. */
elf_properties (abfd) = NULL;
- return FALSE;
+ return false;
}
prop = _bfd_elf_get_property (abfd, type, datasz);
- elf_has_no_copy_on_protected (abfd) = TRUE;
+ elf_has_no_copy_on_protected (abfd) = true;
prop->pr_kind = property_number;
goto next;
default:
+ if ((type >= GNU_PROPERTY_UINT32_AND_LO
+ && type <= GNU_PROPERTY_UINT32_AND_HI)
+ || (type >= GNU_PROPERTY_UINT32_OR_LO
+ && type <= GNU_PROPERTY_UINT32_OR_HI))
+ {
+ if (datasz != 4)
+ {
+ _bfd_error_handler
+ (_("error: %pB: <corrupt property (0x%x) size: 0x%x>"),
+ abfd, type, datasz);
+ /* Clear all properties. */
+ elf_properties (abfd) = NULL;
+ return false;
+ }
+ prop = _bfd_elf_get_property (abfd, type, datasz);
+ prop->u.number |= bfd_h_get_32 (abfd, ptr);
+ prop->pr_kind = property_number;
+ goto next;
+ }
break;
}
}
(_("warning: %pB: unsupported GNU_PROPERTY_TYPE (%ld) type: 0x%x"),
abfd, note->type, type);
-next:
+ next:
ptr += (datasz + (align_size - 1)) & ~ (align_size - 1);
}
- return TRUE;
+ return true;
}
/* Merge GNU property BPROP with APROP. If APROP isn't NULL, return TRUE
if APROP is updated. Otherwise, return TRUE if BPROP should be merged
with ABFD. */
-static bfd_boolean
-elf_merge_gnu_properties (struct bfd_link_info *info, bfd *abfd,
+static bool
+elf_merge_gnu_properties (struct bfd_link_info *info, bfd *abfd, bfd *bbfd,
elf_property *aprop, elf_property *bprop)
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type;
+ unsigned int number;
+ bool updated;
if (bed->merge_gnu_properties != NULL
&& pr_type >= GNU_PROPERTY_LOPROC
&& pr_type < GNU_PROPERTY_LOUSER)
- return bed->merge_gnu_properties (info, abfd, aprop, bprop);
+ return bed->merge_gnu_properties (info, abfd, bbfd, aprop, bprop);
switch (pr_type)
{
if (bprop->u.number > aprop->u.number)
{
aprop->u.number = bprop->u.number;
- return TRUE;
+ return true;
}
break;
}
return aprop == NULL;
default:
+ updated = false;
+ if (pr_type >= GNU_PROPERTY_UINT32_OR_LO
+ && pr_type <= GNU_PROPERTY_UINT32_OR_HI)
+ {
+ if (aprop != NULL && bprop != NULL)
+ {
+ number = aprop->u.number;
+ aprop->u.number = number | bprop->u.number;
+ /* Remove the property if all bits are empty. */
+ if (aprop->u.number == 0)
+ {
+ aprop->pr_kind = property_remove;
+ updated = true;
+ }
+ else
+ updated = number != (unsigned int) aprop->u.number;
+ }
+ else
+ {
+ /* Only one of APROP and BPROP can be NULL. */
+ if (aprop != NULL)
+ {
+ if (aprop->u.number == 0)
+ {
+ /* Remove APROP if all bits are empty. */
+ aprop->pr_kind = property_remove;
+ updated = true;
+ }
+ }
+ else
+ {
+ /* Return TRUE if APROP is NULL and all bits of BPROP
+ aren't empty to indicate that BPROP should be added
+ to ABFD. */
+ updated = bprop->u.number != 0;
+ }
+ }
+ return updated;
+ }
+ else if (pr_type >= GNU_PROPERTY_UINT32_AND_LO
+ && pr_type <= GNU_PROPERTY_UINT32_AND_HI)
+ {
+ /* Only one of APROP and BPROP can be NULL:
+ 1. APROP & BPROP when both APROP and BPROP aren't NULL.
+ 2. If APROP is NULL, remove x86 feature.
+ 3. Otherwise, do nothing.
+ */
+ if (aprop != NULL && bprop != NULL)
+ {
+ number = aprop->u.number;
+ aprop->u.number = number & bprop->u.number;
+ updated = number != (unsigned int) aprop->u.number;
+ /* Remove the property if all feature bits are cleared. */
+ if (aprop->u.number == 0)
+ aprop->pr_kind = property_remove;
+ }
+ else
+ {
+ /* There should be no AND properties since some input
+ doesn't have them. */
+ if (aprop != NULL)
+ {
+ aprop->pr_kind = property_remove;
+ updated = true;
+ }
+ }
+ return updated;
+ }
+
/* Never should happen. */
abort ();
}
- return FALSE;
+ return false;
}
-/* Return the property of TYPE on *LISTP and remove it from *LISTP.
- Return NULL if not found. */
+/* Return the property of TYPE on *LISTP and remove it from *LISTP if RM is
+ true. Return NULL if not found. */
static elf_property *
elf_find_and_remove_property (elf_property_list **listp,
- unsigned int type)
+ unsigned int type, bool rm)
{
elf_property_list *list;
if (type == list->property.pr_type)
{
/* Remove this property. */
- *listp = list->next;
+ if (rm)
+ *listp = list->next;
return &list->property;
}
else if (type < list->property.pr_type)
return NULL;
}
-/* Merge GNU property list *LISTP with ABFD. */
+/* Merge GNU property list *LISTP in ABFD with FIRST_PBFD. */
static void
-elf_merge_gnu_property_list (struct bfd_link_info *info, bfd *abfd,
- elf_property_list **listp)
+elf_merge_gnu_property_list (struct bfd_link_info *info, bfd *first_pbfd,
+ bfd *abfd, elf_property_list **listp)
{
elf_property_list *p, **lastp;
elf_property *pr;
+ bool number_p;
+ bfd_vma number = 0;
- /* Merge each GNU property in ABFD with the one on *LISTP. */
- lastp = &elf_properties (abfd);
+ /* Merge each GNU property in FIRST_PBFD with the one on *LISTP. */
+ lastp = &elf_properties (first_pbfd);
for (p = *lastp; p; p = p->next)
+ if (p->property.pr_kind != property_remove)
+ {
+ if (p->property.pr_kind == property_number)
+ {
+ number_p = true;
+ number = p->property.u.number;
+ }
+ else
+ number_p = false;
+ pr = elf_find_and_remove_property (listp, p->property.pr_type,
+ true);
+ /* Pass NULL to elf_merge_gnu_properties for the property which
+ isn't on *LISTP. */
+ elf_merge_gnu_properties (info, first_pbfd, abfd, &p->property, pr);
+ if (p->property.pr_kind == property_remove)
+ {
+ if (info->has_map_file)
+ {
+ if (number_p)
+ {
+ if (pr != NULL)
+ info->callbacks->minfo
+ (_("Removed property %W to merge %pB (0x%v) "
+ "and %pB (0x%v)\n"),
+ (bfd_vma) p->property.pr_type, first_pbfd,
+ number, abfd, pr->u.number);
+ else
+ info->callbacks->minfo
+ (_("Removed property %W to merge %pB (0x%v) "
+ "and %pB (not found)\n"),
+ (bfd_vma) p->property.pr_type, first_pbfd,
+ number, abfd);
+ }
+ else
+ {
+ if (pr != NULL)
+ info->callbacks->minfo
+ (_("Removed property %W to merge %pB and %pB\n"),
+ (bfd_vma) p->property.pr_type, first_pbfd, abfd);
+ else
+ info->callbacks->minfo
+ (_("Removed property %W to merge %pB and %pB "
+ "(not found)\n"),
+ (bfd_vma) p->property.pr_type, first_pbfd, abfd);
+ }
+ }
+
+ /* Remove this property. */
+ *lastp = p->next;
+ continue;
+ }
+ else if (number_p)
+ {
+ if (pr != NULL)
+ {
+ if (p->property.u.number != number
+ || p->property.u.number != pr->u.number)
+ info->callbacks->minfo
+ (_("Updated property %W (0x%v) to merge %pB (0x%v) "
+ "and %pB (0x%v)\n"),
+ (bfd_vma) p->property.pr_type, p->property.u.number,
+ first_pbfd, number, abfd, pr->u.number);
+ }
+ else
+ {
+ if (p->property.u.number != number)
+ info->callbacks->minfo
+ (_("Updated property %W (%v) to merge %pB (0x%v) "
+ "and %pB (not found)\n"),
+ (bfd_vma) p->property.pr_type, p->property.u.number,
+ first_pbfd, number, abfd);
+ }
+ }
+ lastp = &p->next;
+ }
+
+ /* Merge the remaining properties on *LISTP with FIRST_PBFD. */
+ for (p = *listp; p != NULL; p = p->next)
{
- pr = elf_find_and_remove_property (listp, p->property.pr_type);
- /* Pass NULL to elf_merge_gnu_properties for the property which
- isn't on *LISTP. */
- elf_merge_gnu_properties (info, abfd, &p->property, pr);
- if (p->property.pr_kind == property_remove)
+ if (p->property.pr_kind == property_number)
{
- /* Remove this property. */
- *lastp = p->next;
- continue;
+ number_p = true;
+ number = p->property.u.number;
}
- lastp = &p->next;
- }
-
- /* Merge the remaining properties on *LISTP with ABFD. */
- for (p = *listp; p != NULL; p = p->next)
- if (elf_merge_gnu_properties (info, abfd, NULL, &p->property))
- {
- if (p->property.pr_type == GNU_PROPERTY_NO_COPY_ON_PROTECTED)
- elf_has_no_copy_on_protected (abfd) = TRUE;
+ else
+ number_p = false;
- pr = _bfd_elf_get_property (abfd, p->property.pr_type,
- p->property.pr_datasz);
- /* It must be a new property. */
- if (pr->pr_kind != property_unknown)
- abort ();
- /* Add a new property. */
- *pr = p->property;
- }
+ if (elf_merge_gnu_properties (info, first_pbfd, abfd, NULL, &p->property))
+ {
+ if (p->property.pr_type == GNU_PROPERTY_NO_COPY_ON_PROTECTED)
+ elf_has_no_copy_on_protected (first_pbfd) = true;
+
+ pr = _bfd_elf_get_property (first_pbfd, p->property.pr_type,
+ p->property.pr_datasz);
+ /* It must be a new property. */
+ if (pr->pr_kind != property_unknown)
+ abort ();
+ /* Add a new property. */
+ *pr = p->property;
+ }
+ else
+ {
+ pr = elf_find_and_remove_property (&elf_properties (first_pbfd),
+ p->property.pr_type,
+ false);
+ if (pr == NULL)
+ {
+ if (number_p)
+ info->callbacks->minfo
+ (_("Removed property %W to merge %pB (not found) and "
+ "%pB (0x%v)\n"),
+ (bfd_vma) p->property.pr_type, first_pbfd, abfd,
+ number);
+ else
+ info->callbacks->minfo
+ (_("Removed property %W to merge %pB and %pB\n"),
+ (bfd_vma) p->property.pr_type, first_pbfd, abfd);
+ }
+ else if (pr->pr_kind != property_remove)
+ abort ();
+ }
+ }
}
/* Get GNU property section size. */
size = descsz;
for (; list != NULL; list = list->next)
{
- /* There are 4 byte type + 4 byte datasz for each property. */
unsigned int datasz;
+ /* Check if this property should be skipped. */
+ if (list->property.pr_kind == property_remove)
+ continue;
+ /* There are 4 byte type + 4 byte datasz for each property. */
if (list->property.pr_type == GNU_PROPERTY_STACK_SIZE)
datasz = align_size;
else
size = descsz;
for (; list != NULL; list = list->next)
{
+ /* Check if this property should be skipped. */
+ if (list->property.pr_kind == property_remove)
+ continue;
/* There are 4 byte type + 4 byte datasz for each property. */
if (list->property.pr_type == GNU_PROPERTY_STACK_SIZE)
datasz = align_size;
bfd *abfd, *first_pbfd = NULL;
elf_property_list *list;
asection *sec;
- bfd_boolean has_properties = FALSE;
+ bool has_properties = false;
const struct elf_backend_data *bed
= get_elf_backend_data (info->output_bfd);
unsigned int elfclass = bed->s->elfclass;
&& (abfd->flags & DYNAMIC) == 0
&& elf_properties (abfd) != NULL)
{
- has_properties = TRUE;
+ has_properties = true;
/* Ignore GNU properties from ELF objects with different machine
code or class. Also skip objects without a GNU_PROPERTY note
return NULL;
/* Merge .note.gnu.property sections. */
+ info->callbacks->minfo (_("\n"));
+ info->callbacks->minfo (_("Merging program properties\n"));
+ info->callbacks->minfo (_("\n"));
+
for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
- if (abfd != first_pbfd && (abfd->flags & DYNAMIC) == 0)
+ if (abfd != first_pbfd
+ && (abfd->flags & (DYNAMIC | BFD_PLUGIN | BFD_LINKER_CREATED)) == 0)
{
elf_property_list *null_ptr = NULL;
elf_property_list **listp = &null_ptr;
when all properties are from ELF objects with different
machine code or class. */
if (first_pbfd != NULL)
- elf_merge_gnu_property_list (info, first_pbfd, listp);
+ elf_merge_gnu_property_list (info, first_pbfd, abfd, listp);
if (list != NULL)
{
{
bfd_size_type size;
bfd_byte *contents;
- unsigned int align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4;
+ unsigned int align_size = elfclass == ELFCLASS64 ? 8 : 4;
sec = bfd_get_section_by_name (first_pbfd,
NOTE_GNU_PROPERTY_SECTION_NAME);
return NULL;
}
+ /* Fix up GNU properties. */
+ if (bed->fixup_gnu_properties)
+ bed->fixup_gnu_properties (info, &elf_properties (first_pbfd));
+
+ if (elf_properties (first_pbfd) == NULL)
+ {
+ /* Discard .note.gnu.property section if all properties have
+ been removed. */
+ sec->output_section = bfd_abs_section_ptr;
+ return NULL;
+ }
+
/* Compute the section size. */
list = elf_properties (first_pbfd);
size = elf_get_gnu_property_section_size (list, align_size);
/* If GNU_PROPERTY_NO_COPY_ON_PROTECTED is set, protected data
symbol is defined in the shared object. */
if (elf_has_no_copy_on_protected (first_pbfd))
- info->extern_protected_data = FALSE;
+ info->extern_protected_data = false;
}
return first_pbfd;
/* Convert GNU properties. */
-bfd_boolean
+bool
_bfd_elf_convert_gnu_properties (bfd *ibfd, asection *isec,
bfd *obfd, bfd_byte **ptr,
bfd_size_type *ptr_size)
align_shift = bed->s->elfclass == ELFCLASS64 ? 3 : 2;
/* Get the output .note.gnu.property section size. */
- size = bfd_get_section_size (isec->output_section);
+ size = bfd_section_size (isec->output_section);
/* Update the output .note.gnu.property section alignment. */
- bfd_set_section_alignment (obfd, isec->output_section, align_shift);
+ bfd_set_section_alignment (isec->output_section, align_shift);
- if (size > bfd_get_section_size (isec))
+ if (size > bfd_section_size (isec))
{
contents = (bfd_byte *) bfd_malloc (size);
+ if (contents == NULL)
+ return false;
free (*ptr);
*ptr = contents;
}
/* Generate the output .note.gnu.property section. */
elf_write_gnu_properties (ibfd, contents, list, size, 1 << align_shift);
- return TRUE;
+ return true;
}