X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=bfd%2Felf-ifunc.c;h=c8b385db529d1dfe1877514872fbeeccaaeb452f;hb=924cf858c94ebc3f54e1e2e0710099fb94e2c901;hp=564e46459d520d03a56140bdef2461c03aae16a4;hpb=695344c018c8e462280c47a644df02ea472b0a4e;p=binutils-gdb.git diff --git a/bfd/elf-ifunc.c b/bfd/elf-ifunc.c index 564e46459d5..c8b385db529 100644 --- a/bfd/elf-ifunc.c +++ b/bfd/elf-ifunc.c @@ -1,5 +1,5 @@ /* 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. @@ -30,7 +30,7 @@ /* 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; @@ -39,7 +39,7 @@ _bfd_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info) 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; @@ -62,9 +62,8 @@ _bfd_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info) 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 @@ -73,8 +72,8 @@ _bfd_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info) 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, @@ -82,9 +81,8 @@ _bfd_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info) ? ".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 @@ -94,45 +92,49 @@ _bfd_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info) 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) @@ -140,12 +142,12 @@ _bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info, 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); @@ -156,17 +158,17 @@ _bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *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; } @@ -181,7 +183,7 @@ _bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info, 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 @@ -194,10 +196,10 @@ _bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info, 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; @@ -251,8 +253,6 @@ keep: if (!need_dynreloc || !h->non_got_ref) *head = NULL; - readonly_dynrelocs_against_ifunc = FALSE; - /* Finally, allocate space. */ p = *head; if (p != NULL) @@ -260,17 +260,13 @@ keep: 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. @@ -286,9 +282,6 @@ keep: } } - 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 @@ -353,130 +346,5 @@ keep: } } - 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; }