/* ELF program property support.
- Copyright (C) 2017-2019 Free Software Foundation, Inc.
+ Copyright (C) 2017-2022 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;
+ if (type == GNU_PROPERTY_1_NEEDED
+ && ((prop->u.number
+ & GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS)
+ != 0))
+ {
+ elf_has_indirect_extern_access (abfd) = true;
+ /* GNU_PROPERTY_NO_COPY_ON_PROTECTED is implied. */
+ elf_has_no_copy_on_protected (abfd) = true;
+ }
+ 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
+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
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, bfd_boolean remove)
+ unsigned int type, bool rm)
{
elf_property_list *list;
if (type == list->property.pr_type)
{
/* Remove this property. */
- if (remove)
+ if (rm)
*listp = list->next;
return &list->property;
}
{
elf_property_list *p, **lastp;
elf_property *pr;
- bfd_boolean number_p;
+ bool number_p;
bfd_vma number = 0;
/* Merge each GNU property in FIRST_PBFD with the one on *LISTP. */
{
if (p->property.pr_kind == property_number)
{
- number_p = TRUE;
+ number_p = true;
number = p->property.u.number;
}
else
- number_p = FALSE;
+ number_p = false;
pr = elf_find_and_remove_property (listp, p->property.pr_type,
- TRUE);
+ 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);
(bfd_vma) p->property.pr_type, first_pbfd, abfd);
}
}
- else
- {
- /* Remove this property. */
- *lastp = p->next;
- continue;
- }
+
+ /* Remove this property. */
+ *lastp = p->next;
+ continue;
}
else if (number_p)
{
{
if (p->property.pr_kind == property_number)
{
- number_p = TRUE;
+ number_p = true;
number = p->property.u.number;
}
else
- number_p = FALSE;
+ number_p = false;
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;
+ elf_has_no_copy_on_protected (first_pbfd) = true;
pr = _bfd_elf_get_property (first_pbfd, p->property.pr_type,
p->property.pr_datasz);
{
pr = elf_find_and_remove_property (&elf_properties (first_pbfd),
p->property.pr_type,
- FALSE);
+ false);
if (pr == NULL)
{
if (number_p)
/* Write GNU properties. */
static void
-elf_write_gnu_properties (bfd *abfd, bfd_byte *contents,
+elf_write_gnu_properties (struct bfd_link_info *info,
+ bfd *abfd, bfd_byte *contents,
elf_property_list *list, unsigned int size,
unsigned int align_size)
{
break;
case 4:
+ /* Save the pointer to GNU_PROPERTY_1_NEEDED so that it
+ can be updated later if needed. */
+ if (info != NULL
+ && list->property.pr_type == GNU_PROPERTY_1_NEEDED)
+ info->needed_1_p = contents + size;
bfd_h_put_32 (abfd, list->property.u.number,
contents + size);
break;
bfd *
_bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
{
- bfd *abfd, *first_pbfd = NULL;
+ bfd *abfd, *first_pbfd = NULL, *elf_bfd = 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;
int elf_machine_code = bed->elf_machine_code;
+ elf_property *p;
/* Find the first relocatable ELF input with GNU properties. */
for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
&& (abfd->flags & DYNAMIC) == 0
- && elf_properties (abfd) != NULL)
+ && (elf_machine_code
+ == get_elf_backend_data (abfd)->elf_machine_code)
+ && (elfclass == get_elf_backend_data (abfd)->s->elfclass))
{
- has_properties = TRUE;
-
/* Ignore GNU properties from ELF objects with different machine
code or class. Also skip objects without a GNU_PROPERTY note
section. */
- if ((elf_machine_code
- == get_elf_backend_data (abfd)->elf_machine_code)
- && (elfclass
- == get_elf_backend_data (abfd)->s->elfclass)
- && bfd_get_section_by_name (abfd,
- NOTE_GNU_PROPERTY_SECTION_NAME) != NULL
- )
+ elf_bfd = abfd;
+
+ if (elf_properties (abfd) != NULL)
{
- /* Keep .note.gnu.property section in FIRST_PBFD. */
- first_pbfd = abfd;
- break;
+ has_properties = true;
+
+ if (bfd_get_section_by_name (abfd,
+ NOTE_GNU_PROPERTY_SECTION_NAME)
+ != NULL)
+ {
+ /* Keep .note.gnu.property section in FIRST_PBFD. */
+ first_pbfd = abfd;
+ break;
+ }
}
}
+ if (info->indirect_extern_access > 0 && elf_bfd != NULL)
+ {
+ /* Support -z indirect-extern-access. */
+ if (first_pbfd == NULL)
+ {
+ sec = bfd_make_section_with_flags (elf_bfd,
+ NOTE_GNU_PROPERTY_SECTION_NAME,
+ (SEC_ALLOC
+ | SEC_LOAD
+ | SEC_IN_MEMORY
+ | SEC_READONLY
+ | SEC_HAS_CONTENTS
+ | SEC_DATA));
+ if (sec == NULL)
+ info->callbacks->einfo (_("%F%P: failed to create GNU property section\n"));
+
+ if (!bfd_set_section_alignment (sec,
+ elfclass == ELFCLASS64 ? 3 : 2))
+ info->callbacks->einfo (_("%F%pA: failed to align section\n"),
+ sec);
+
+ elf_section_type (sec) = SHT_NOTE;
+ first_pbfd = elf_bfd;
+ has_properties = true;
+ }
+
+ p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_1_NEEDED, 4);
+ if (p->pr_kind == property_unknown)
+ {
+ /* Create GNU_PROPERTY_1_NEEDED. */
+ p->u.number
+ = GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
+ p->pr_kind = property_number;
+ }
+ else
+ p->u.number
+ |= GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
+ }
+
/* Do nothing if there is no .note.gnu.property section. */
if (!has_properties)
return NULL;
if N > 0. */
if (info->stacksize > 0)
{
- elf_property *p;
bfd_vma stacksize = info->stacksize;
p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_STACK_SIZE,
sec->size = size;
contents = (bfd_byte *) bfd_zalloc (first_pbfd, size);
- elf_write_gnu_properties (first_pbfd, contents, list, size,
+ if (info->indirect_extern_access <= 0)
+ {
+ /* Get GNU_PROPERTY_1_NEEDED properties. */
+ p = elf_find_and_remove_property (&elf_properties (first_pbfd),
+ GNU_PROPERTY_1_NEEDED, false);
+ if (p != NULL)
+ {
+ if (info->indirect_extern_access < 0)
+ {
+ /* Set indirect_extern_access to 1 to indicate that
+ it is turned on by input properties. */
+ if ((p->u.number
+ & GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS)
+ != 0)
+ info->indirect_extern_access = 1;
+ }
+ else
+ /* Turn off indirect external access. */
+ p->u.number
+ &= ~GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
+ }
+ }
+
+ elf_write_gnu_properties (info, first_pbfd, contents, list, size,
align_size);
/* Cache the section contents for elf_link_input_bfd. */
/* 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;
+
+ if (info->indirect_extern_access > 0)
+ {
+ /* For indirect external access, don't generate copy
+ relocations. NB: Set to nocopyreloc to 2 to indicate
+ that it is implied by indirect_extern_access. */
+ info->nocopyreloc = 2;
+ 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;
}
*ptr_size = size;
/* Generate the output .note.gnu.property section. */
- elf_write_gnu_properties (ibfd, contents, list, size, 1 << align_shift);
+ elf_write_gnu_properties (NULL, ibfd, contents, list, size,
+ 1 << align_shift);
- return TRUE;
+ return true;
}