/* ELF STT_GNU_IFUNC support.
- Copyright (C) 2009-2016 Free Software Foundation, Inc.
+ Copyright (C) 2009-2022 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
/* Create sections needed by STT_GNU_IFUNC symbol. */
-bfd_boolean
+bool
_bfd_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info)
{
flagword flags, pltflags;
struct elf_link_hash_table *htab = elf_hash_table (info);
if (htab->irelifunc != NULL || htab->iplt != NULL)
- return TRUE;
+ return true;
flags = bed->dynamic_sec_flags;
pltflags = flags;
s = bfd_make_section_with_flags (abfd, rel_sec,
flags | SEC_READONLY);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s,
- bed->s->log_file_align))
- return FALSE;
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
+ return false;
htab->irelifunc = s;
}
else
for static executables. */
s = bfd_make_section_with_flags (abfd, ".iplt", pltflags);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment))
- return FALSE;
+ || !bfd_set_section_alignment (s, bed->plt_alignment))
+ return false;
htab->iplt = s;
s = bfd_make_section_with_flags (abfd,
? ".rela.iplt" : ".rel.iplt"),
flags | SEC_READONLY);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s,
- bed->s->log_file_align))
- return FALSE;
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
+ return false;
htab->irelplt = s;
/* We don't need the .igot section if we have the .igot.plt
else
s = bfd_make_section_with_flags (abfd, ".igot", flags);
if (s == NULL
- || !bfd_set_section_alignment (abfd, s,
- bed->s->log_file_align))
- return FALSE;
+ || !bfd_set_section_alignment (s, bed->s->log_file_align))
+ return false;
htab->igotplt = s;
}
- return TRUE;
+ return true;
}
/* Allocate space in .plt, .got and associated reloc sections for
dynamic relocs against a STT_GNU_IFUNC symbol definition. */
-bfd_boolean
+bool
_bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
struct elf_link_hash_entry *h,
struct elf_dyn_relocs **head,
- bfd_boolean *readonly_dynrelocs_against_ifunc_p,
unsigned int plt_entry_size,
unsigned int plt_header_size,
unsigned int got_entry_size,
- bfd_boolean avoid_plt)
+ bool avoid_plt)
{
asection *plt, *gotplt, *relplt;
struct elf_dyn_relocs *p;
unsigned int sizeof_reloc;
const struct elf_backend_data *bed;
struct elf_link_hash_table *htab;
- bfd_boolean readonly_dynrelocs_against_ifunc;
/* If AVOID_PLT is TRUE, don't use PLT if possible. */
- bfd_boolean use_plt = !avoid_plt || h->plt.refcount > 0;
- bfd_boolean need_dynreloc = !use_plt || bfd_link_pic (info);
+ bool use_plt = !avoid_plt || h->plt.refcount > 0;
+ bool need_dynreloc = !use_plt || bfd_link_pic (info);
/* When a PIC object references a STT_GNU_IFUNC symbol defined
in executable or it isn't referenced via PLT, the address of
the resolved function may be used. But in non-PIC executable,
the address of its .plt slot may be used. Pointer equality may
not work correctly. PIE or non-PLT reference should be used if
- pointer equality is required here. */
+ pointer equality is required here.
+
+ If STT_GNU_IFUNC symbol is defined in position-dependent executable,
+ backend should change it to the normal function and set its address
+ to its PLT entry which should be resolved by R_*_IRELATIVE at
+ run-time. All external references should be resolved to its PLT in
+ executable. */
if (!need_dynreloc
+ && !(bfd_link_pde (info) && h->def_regular)
&& (h->dynindx != -1
|| info->export_dynamic)
&& h->pointer_equality_needed)
{
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer "
- "equality in `%B' can not be used when making an "
+ "equality in `%pB' can not be used when making an "
"executable; recompile with -fPIE and relink with -pie\n"),
h->root.root.string,
h->root.u.def.section->owner);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return false;
}
htab = elf_hash_table (info);
reference. */
if (need_dynreloc && h->ref_regular)
{
- bfd_boolean keep = FALSE;
+ bool keep = false;
for (p = *head; p != NULL; p = p->next)
if (p->count)
{
h->non_got_ref = 1;
/* Need dynamic relocations for non-GOT reference. */
- keep = TRUE;
+ keep = true;
if (p->pc_count)
{
/* Must use PLT for PC-relative reference. */
- use_plt = TRUE;
+ use_plt = true;
need_dynreloc = bfd_link_pic (info);
break;
}
h->got = htab->init_got_offset;
h->plt = htab->init_plt_offset;
*head = NULL;
- return TRUE;
+ return true;
}
/* Return and discard space for dynamic relocations against it if
h->got = htab->init_got_offset;
h->plt = htab->init_plt_offset;
*head = NULL;
- return TRUE;
+ return true;
}
-keep:
+ keep:
bed = get_elf_backend_data (info->output_bfd);
if (bed->rela_plts_and_copies_p)
sizeof_reloc = bed->s->sizeof_rela;
if (!need_dynreloc || !h->non_got_ref)
*head = NULL;
- readonly_dynrelocs_against_ifunc = FALSE;
-
/* Finally, allocate space. */
p = *head;
if (p != NULL)
bfd_size_type count = 0;
do
{
- if (!readonly_dynrelocs_against_ifunc)
- {
- asection *s = p->sec->output_section;
- if (s != NULL && (s->flags & SEC_READONLY) != 0)
- readonly_dynrelocs_against_ifunc = TRUE;
- }
count += p->count;
p = p->next;
}
while (p != NULL);
+ htab->ifunc_resolvers = count != 0;
+
/* Dynamic relocations are stored in
1. .rel[a].ifunc section in PIC object.
2. .rel[a].got section in dynamic executable.
}
}
- if (readonly_dynrelocs_against_ifunc_p)
- *readonly_dynrelocs_against_ifunc_p = readonly_dynrelocs_against_ifunc;
-
/* For STT_GNU_IFUNC symbol, .got.plt has the real function address
and .got has the PLT entry adddress. We will load the GOT entry
with the PLT entry in finish_dynamic_symbol if it is used. For
}
}
- return TRUE;
-}
-
-/* Similar to _bfd_elf_get_synthetic_symtab, optimized for unsorted PLT
- entries. PLT is the PLT section. PLT_SYM_VAL is a function pointer
- which returns an array of PLT entry symbol values. */
-
-long
-_bfd_elf_ifunc_get_synthetic_symtab
- (bfd *abfd, long symcount ATTRIBUTE_UNUSED,
- asymbol **syms ATTRIBUTE_UNUSED, long dynsymcount, asymbol **dynsyms,
- asymbol **ret, asection *plt,
- bfd_vma *(*get_plt_sym_val) (bfd *, asymbol **, asection *, asection *))
-{
- const struct elf_backend_data *bed = get_elf_backend_data (abfd);
- asection *relplt;
- asymbol *s;
- const char *relplt_name;
- bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
- arelent *p;
- long count, i, n;
- size_t size;
- Elf_Internal_Shdr *hdr;
- char *names;
- bfd_vma *plt_sym_val;
-
- *ret = NULL;
-
- if (plt == NULL)
- return 0;
-
- if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0)
- return 0;
-
- if (dynsymcount <= 0)
- return 0;
-
- relplt_name = bed->relplt_name;
- if (relplt_name == NULL)
- relplt_name = bed->rela_plts_and_copies_p ? ".rela.plt" : ".rel.plt";
- relplt = bfd_get_section_by_name (abfd, relplt_name);
- if (relplt == NULL)
- return 0;
-
- hdr = &elf_section_data (relplt)->this_hdr;
- if (hdr->sh_link != elf_dynsymtab (abfd)
- || (hdr->sh_type != SHT_REL && hdr->sh_type != SHT_RELA))
- return 0;
-
- slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
- if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
- return -1;
-
- count = relplt->size / hdr->sh_entsize;
- size = count * sizeof (asymbol);
- p = relplt->relocation;
- for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
- {
- size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
- if (p->addend != 0)
- {
-#ifdef BFD64
- size += sizeof ("+0x") - 1 + 8 + 8 * (bed->s->elfclass == ELFCLASS64);
-#else
- size += sizeof ("+0x") - 1 + 8;
-#endif
- }
- }
-
- plt_sym_val = get_plt_sym_val (abfd, dynsyms, plt, relplt);
- if (plt_sym_val == NULL)
- return -1;
-
- s = *ret = (asymbol *) bfd_malloc (size);
- if (s == NULL)
- {
- free (plt_sym_val);
- return -1;
- }
-
- names = (char *) (s + count);
- p = relplt->relocation;
- n = 0;
- for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
- {
- size_t len;
- bfd_vma addr;
-
- addr = plt_sym_val[i];
- if (addr == (bfd_vma) -1)
- continue;
-
- *s = **p->sym_ptr_ptr;
- /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since
- we are defining a symbol, ensure one of them is set. */
- if ((s->flags & BSF_LOCAL) == 0)
- s->flags |= BSF_GLOBAL;
- s->flags |= BSF_SYNTHETIC;
- s->section = plt;
- s->value = addr - plt->vma;
- s->name = names;
- s->udata.p = NULL;
- len = strlen ((*p->sym_ptr_ptr)->name);
- memcpy (names, (*p->sym_ptr_ptr)->name, len);
- names += len;
- if (p->addend != 0)
- {
- char buf[30], *a;
-
- memcpy (names, "+0x", sizeof ("+0x") - 1);
- names += sizeof ("+0x") - 1;
- bfd_sprintf_vma (abfd, buf, p->addend);
- for (a = buf; *a == '0'; ++a)
- ;
- len = strlen (a);
- memcpy (names, a, len);
- names += len;
- }
- memcpy (names, "@plt", sizeof ("@plt"));
- names += sizeof ("@plt");
- ++s, ++n;
- }
-
- free (plt_sym_val);
-
- return n;
+ return true;
}