From e03a8ed8034fdfbbf7f73ae2fbf7fe29b60c6c5a Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 18 Jun 2009 00:45:14 +0000 Subject: [PATCH] 2009-06-17 H.J. Lu * elf-bfd.h (_bfd_elf_allocate_ifunc_dyn_relocs): New. * elf-ifunc.c (_bfd_elf_allocate_ifunc_dyn_relocs): Likewise. * elf32-i386.c (elf_i386_allocate_dynrelocs): Use it. * elf64-x86-64.c (elf64_x86_64_allocate_dynrelocs): Likewise. 2009-06-17 H.J. Lu * elf-bfd.h (_bfd_elf_create_ifunc_dyn_reloc): New. * elf-ifunc.c (_bfd_elf_create_ifunc_dyn_reloc): Likewise. * elf32-i386.c (elf_i386_check_relocs): Use it. * elf64-x86-64.c (elf64_x86_64_check_relocs): Likewise. 2009-06-17 H.J. Lu * elf-bfd.h (elf_dyn_relocs): New. * elf32-i386.c (elf_i386_dyn_relocs): Removed. (elf_i386_link_hash_entry): Replace elf_i386_dyn_relocs with elf_dyn_relocs. (elf_i386_copy_indirect_symbol): Likewise. (elf_i386_check_relocs): Likewise. (elf_i386_gc_sweep_hook): Likewise. (elf_i386_allocate_dynrelocs): Likewise. (elf_i386_readonly_dynrelocs): Likewise. (elf_i386_size_dynamic_sections): Likewise. * elf64-x86-64.c (elf64_x86_64_dyn_relocs): Removed. (elf64_x86_64_link_hash_entry): Replace elf64_x86_64_dyn_relocs with elf_dyn_relocs. (elf64_x86_64_copy_indirect_symbol): Updated. (elf64_x86_64_check_relocs): Likewise. (elf64_x86_64_gc_sweep_hook): Likewise. (elf64_x86_64_adjust_dynamic_symbol): Likewise. (elf64_x86_64_allocate_dynrelocs): Likewise. (elf64_x86_64_readonly_dynrelocs): Likewise. (elf64_x86_64_size_dynamic_sections): Likewise. --- bfd/ChangeLog | 39 +++++++++ bfd/elf-bfd.h | 26 ++++++ bfd/elf-ifunc.c | 182 +++++++++++++++++++++++++++++++++++++++ bfd/elf32-i386.c | 205 +++++-------------------------------------- bfd/elf64-x86-64.c | 210 ++++++--------------------------------------- 5 files changed, 294 insertions(+), 368 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 15e73e9fb2..6458ccfba4 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,42 @@ +2009-06-17 H.J. Lu + + * elf-bfd.h (_bfd_elf_allocate_ifunc_dyn_relocs): New. + * elf-ifunc.c (_bfd_elf_allocate_ifunc_dyn_relocs): Likewise. + * elf32-i386.c (elf_i386_allocate_dynrelocs): Use it. + * elf64-x86-64.c (elf64_x86_64_allocate_dynrelocs): Likewise. + +2009-06-17 H.J. Lu + + * elf-bfd.h (_bfd_elf_create_ifunc_dyn_reloc): New. + * elf-ifunc.c (_bfd_elf_create_ifunc_dyn_reloc): Likewise. + * elf32-i386.c (elf_i386_check_relocs): Use it. + * elf64-x86-64.c (elf64_x86_64_check_relocs): Likewise. + +2009-06-17 H.J. Lu + + * elf-bfd.h (elf_dyn_relocs): New. + + * elf32-i386.c (elf_i386_dyn_relocs): Removed. + (elf_i386_link_hash_entry): Replace elf_i386_dyn_relocs with + elf_dyn_relocs. + (elf_i386_copy_indirect_symbol): Likewise. + (elf_i386_check_relocs): Likewise. + (elf_i386_gc_sweep_hook): Likewise. + (elf_i386_allocate_dynrelocs): Likewise. + (elf_i386_readonly_dynrelocs): Likewise. + (elf_i386_size_dynamic_sections): Likewise. + + * elf64-x86-64.c (elf64_x86_64_dyn_relocs): Removed. + (elf64_x86_64_link_hash_entry): Replace elf64_x86_64_dyn_relocs + with elf_dyn_relocs. + (elf64_x86_64_copy_indirect_symbol): Updated. + (elf64_x86_64_check_relocs): Likewise. + (elf64_x86_64_gc_sweep_hook): Likewise. + (elf64_x86_64_adjust_dynamic_symbol): Likewise. + (elf64_x86_64_allocate_dynrelocs): Likewise. + (elf64_x86_64_readonly_dynrelocs): Likewise. + (elf64_x86_64_size_dynamic_sections): Likewise. + 2009-06-17 H.J. Lu * elf32-arm.c (create_got_section): Get existing .rela.got diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index b81f009743..d1a23ad999 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -2157,8 +2157,34 @@ extern int _bfd_elf_obj_attrs_arg_type (bfd *, int, int); extern void _bfd_elf_parse_attributes (bfd *, Elf_Internal_Shdr *); extern bfd_boolean _bfd_elf_merge_object_attributes (bfd *, bfd *); +/* The linker may needs to keep track of the number of relocs that it + decides to copy as dynamic relocs in check_relocs for each symbol. + This is so that it can later discard them if they are found to be + unnecessary. We can store the information in a field extending the + regular ELF linker hash table. */ + +struct elf_dyn_relocs +{ + struct elf_dyn_relocs *next; + + /* The input section of the reloc. */ + asection *sec; + + /* Total number of relocs copied for the input section. */ + bfd_size_type count; + + /* Number of pc-relative relocs copied for the input section. */ + bfd_size_type pc_count; +}; + extern bfd_boolean _bfd_elf_create_ifunc_sections (bfd *, struct bfd_link_info *); +extern asection * _bfd_elf_create_ifunc_dyn_reloc + (bfd *, struct bfd_link_info *, asection *sec, asection *sreloc, + struct elf_dyn_relocs **); +extern bfd_boolean _bfd_elf_allocate_ifunc_dyn_relocs + (struct bfd_link_info *, struct elf_link_hash_entry *, + struct elf_dyn_relocs **, unsigned int, unsigned int); /* Large common section. */ extern asection _bfd_elf_large_com_section; diff --git a/bfd/elf-ifunc.c b/bfd/elf-ifunc.c index 4bfc31b55c..b9b50c3628 100644 --- a/bfd/elf-ifunc.c +++ b/bfd/elf-ifunc.c @@ -103,3 +103,185 @@ _bfd_elf_create_ifunc_sections (bfd *abfd, struct bfd_link_info *info) return TRUE; } + +/* For a STT_GNU_IFUNC symbol, create a dynamic reloc section, SRELOC, + for the input section, SEC, and append this reloc to HEAD. */ + +asection * +_bfd_elf_create_ifunc_dyn_reloc (bfd *abfd, struct bfd_link_info *info, + asection *sec, asection *sreloc, + struct elf_dyn_relocs **head) +{ + struct elf_dyn_relocs *p; + struct elf_link_hash_table *htab = elf_hash_table (info); + + if (sreloc == NULL) + { + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + + if (htab->dynobj == NULL) + htab->dynobj = abfd; + + sreloc = _bfd_elf_make_dynamic_reloc_section (sec, htab->dynobj, + bed->s->log_file_align, + abfd, + bed->rela_plts_and_copies_p); + if (sreloc == NULL) + return NULL; + } + + p = *head; + if (p == NULL || p->sec != sec) + { + bfd_size_type amt = sizeof *p; + + p = ((struct elf_dyn_relocs *) bfd_alloc (htab->dynobj, amt)); + if (p == NULL) + return NULL; + p->next = *head; + *head = p; + p->sec = sec; + p->count = 0; + p->pc_count = 0; + } + p->count += 1; + + return sreloc; +} + +/* Allocate space in .plt, .got and associated reloc sections for + dynamic relocs against a STT_GNU_IFUNC symbol definition. */ + +bfd_boolean +_bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info, + struct elf_link_hash_entry *h, + struct elf_dyn_relocs **head, + unsigned int plt_entry_size, + unsigned int got_entry_size) +{ + 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; + + /* When a shared library references a STT_GNU_IFUNC symbol defined + in executable, the address of the resolved function may be used. + But in non-shared executable, the address of its .plt slot may + be used. Pointer equality may not work correctly. PIE should + be used if pointer equality is required here. */ + if (!info->shared + && (h->dynindx != -1 + || info->export_dynamic) + && h->pointer_equality_needed) + { + info->callbacks->einfo + (_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer " + "equality in `%B' 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 and discard space for dynamic relocations against it if + it is never referenced in a non-shared object. */ + if (!h->ref_regular) + { + if (h->plt.refcount > 0 + || h->got.refcount > 0) + abort (); + h->got.offset = (bfd_vma) -1; + *head = NULL; + return TRUE; + } + + bed = get_elf_backend_data (info->output_bfd); + if (bed->rela_plts_and_copies_p) + sizeof_reloc = bed->s->sizeof_rela; + else + sizeof_reloc = bed->s->sizeof_rel; + + htab = elf_hash_table (info); + + /* When building a static executable, use .iplt, .igot.plt and + .rel[a].iplt sections for STT_GNU_IFUNC symbols. */ + if (htab->splt != NULL) + { + plt = htab->splt; + gotplt = htab->sgotplt; + relplt = htab->srelplt; + + /* If this is the first .plt entry, make room for the special + first entry. */ + if (plt->size == 0) + plt->size += plt_entry_size; + } + else + { + plt = htab->iplt; + gotplt = htab->igotplt; + relplt = htab->irelplt; + } + + /* Don't update value of STT_GNU_IFUNC symbol to PLT. We need + the original value for R_*_IRELATIVE. */ + h->plt.offset = plt->size; + + /* Make room for this entry in the .plt/.iplt section. */ + plt->size += plt_entry_size; + + /* We also need to make an entry in the .got.plt/.got.iplt section, + which will be placed in the .got section by the linker script. */ + gotplt->size += got_entry_size; + + /* We also need to make an entry in the .rel[a].plt/.rel[a].iplt + section. */ + relplt->size += sizeof_reloc; + relplt->reloc_count++; + + /* We need dynamic relocation for STT_GNU_IFUNC symbol only when + there is a non-GOT reference in a shared object. */ + if (!info->shared + || !h->non_got_ref) + *head = NULL; + + /* Finally, allocate space. */ + for (p = *head; p != NULL; p = p->next) + htab->irelifunc->size += p->count * sizeof_reloc; + + /* For STT_GNU_IFUNC symbol, .got.plt has the real function addres + 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 + branch, it uses .got.plt. For symbol value, + 1. Use .got.plt in a shared object if it is forced local or not + dynamic. + 2. Use .got.plt in a non-shared object if pointer equality isn't + needed. + 3. Use .got.plt in PIE. + 4. Use .got.plt if .got isn't used. + 5. Otherwise use .got so that it can be shared among different + objects at run-time. + We only need to relocate .got entry in shared object. */ + if ((info->shared + && (h->dynindx == -1 + || h->forced_local)) + || (!info->shared + && !h->pointer_equality_needed) + || (info->executable && info->shared) + || htab->sgot == NULL) + { + /* Use .got.plt. */ + h->got.offset = (bfd_vma) -1; + } + else + { + h->got.offset = htab->sgot->size; + htab->sgot->size += got_entry_size; + if (info->shared) + htab->srelgot->size += sizeof_reloc; + } + + return TRUE; +} diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 60a414237a..32ea287305 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -577,26 +577,6 @@ static const bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] = #define PLTRESOLVE_RELOCS 2 #define PLT_NON_JUMP_SLOT_RELOCS 2 -/* The i386 linker needs to keep track of the number of relocs that it - decides to copy as dynamic relocs in check_relocs for each symbol. - This is so that it can later discard them if they are found to be - unnecessary. We store the information in a field extending the - regular ELF linker hash table. */ - -struct elf_i386_dyn_relocs -{ - struct elf_i386_dyn_relocs *next; - - /* The input section of the reloc. */ - asection *sec; - - /* Total number of relocs copied for the input section. */ - bfd_size_type count; - - /* Number of pc-relative relocs copied for the input section. */ - bfd_size_type pc_count; -}; - /* i386 ELF linker hash entry. */ struct elf_i386_link_hash_entry @@ -604,7 +584,7 @@ struct elf_i386_link_hash_entry struct elf_link_hash_entry elf; /* Track dynamic relocs copied for this symbol. */ - struct elf_i386_dyn_relocs *dyn_relocs; + struct elf_dyn_relocs *dyn_relocs; #define GOT_UNKNOWN 0 #define GOT_NORMAL 1 @@ -919,14 +899,14 @@ elf_i386_copy_indirect_symbol (struct bfd_link_info *info, { if (edir->dyn_relocs != NULL) { - struct elf_i386_dyn_relocs **pp; - struct elf_i386_dyn_relocs *p; + struct elf_dyn_relocs **pp; + struct elf_dyn_relocs *p; /* Add reloc counts against the indirect sym to the direct sym list. Merge any entries against the same section. */ for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) { - struct elf_i386_dyn_relocs *q; + struct elf_dyn_relocs *q; for (q = edir->dyn_relocs; q != NULL; q = q->next) if (q->sec == p->sec) @@ -1407,39 +1387,14 @@ elf_i386_check_relocs (bfd *abfd, h->pointer_equality_needed = 1; if (info->shared) { - struct elf_i386_dyn_relocs *p; - struct elf_i386_dyn_relocs **head; - /* We must copy these reloc types into the output file. Create a reloc section in dynobj and make room for this reloc. */ + sreloc = _bfd_elf_create_ifunc_dyn_reloc + (abfd, info, sec, sreloc, + &((struct elf_i386_link_hash_entry *) h)->dyn_relocs); if (sreloc == NULL) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, htab->elf.dynobj, 2, abfd, FALSE); - - if (sreloc == NULL) - return FALSE; - } - - head = &((struct elf_i386_link_hash_entry *) h)->dyn_relocs; - p = *head; - if (p == NULL || p->sec != sec) - { - bfd_size_type amt = sizeof *p; - p = bfd_alloc (htab->elf.dynobj, amt); - if (p == NULL) - return FALSE; - p->next = *head; - *head = p; - p->sec = sec; - p->count = 0; - p->pc_count = 0; - } - p->count += 1; + return FALSE; } break; @@ -1669,8 +1624,8 @@ elf_i386_check_relocs (bfd *abfd, && (h->root.type == bfd_link_hash_defweak || !h->def_regular))) { - struct elf_i386_dyn_relocs *p; - struct elf_i386_dyn_relocs **head; + struct elf_dyn_relocs *p; + struct elf_dyn_relocs **head; /* We must copy these reloc types into the output file. Create a reloc section in dynobj and make room for @@ -1707,7 +1662,7 @@ elf_i386_check_relocs (bfd *abfd, return FALSE; vpp = &elf_section_data (s)->local_dynrel; - head = (struct elf_i386_dyn_relocs **)vpp; + head = (struct elf_dyn_relocs **)vpp; } p = *head; @@ -1808,8 +1763,8 @@ elf_i386_gc_sweep_hook (bfd *abfd, if (r_symndx >= symtab_hdr->sh_info) { struct elf_i386_link_hash_entry *eh; - struct elf_i386_dyn_relocs **pp; - struct elf_i386_dyn_relocs *p; + struct elf_dyn_relocs **pp; + struct elf_dyn_relocs *p; h = sym_hashes[r_symndx - symtab_hdr->sh_info]; while (h->root.type == bfd_link_hash_indirect @@ -1980,7 +1935,7 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, if (ELIMINATE_COPY_RELOCS && !htab->is_vxworks) { struct elf_i386_link_hash_entry * eh; - struct elf_i386_dyn_relocs *p; + struct elf_dyn_relocs *p; eh = (struct elf_i386_link_hash_entry *) h; for (p = eh->dyn_relocs; p != NULL; p = p->next) @@ -2037,7 +1992,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) struct bfd_link_info *info; struct elf_i386_link_hash_table *htab; struct elf_i386_link_hash_entry *eh; - struct elf_i386_dyn_relocs *p; + struct elf_dyn_relocs *p; if (h->root.type == bfd_link_hash_indirect) return TRUE; @@ -2056,123 +2011,9 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) here if it is defined and referenced in a non-shared object. */ if (h->type == STT_GNU_IFUNC && h->def_regular) - { - asection *plt, *gotplt, *relplt; - - /* When a shared library references a STT_GNU_IFUNC symbol - defined in executable, the address of the resolved function - may be used. But in non-shared executable, the address of - its .plt slot may be used. Pointer equality may not work - correctly. PIE should be used if pointer equality is - required here. */ - if (!info->shared - && (h->dynindx != -1 - || info->export_dynamic) - && h->pointer_equality_needed) - { - info->callbacks->einfo - (_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer " - "equality in `%B' 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 and discard space for dynamic relocations against it if - it is never referenced in a non-shared object. */ - if (!h->ref_regular) - { - if (h->plt.refcount > 0 - || h->got.refcount > 0) - abort (); - h->got.offset = (bfd_vma) -1; - eh->dyn_relocs = NULL; - return TRUE; - } - - /* When building a static executable, use .iplt, .igot.plt and - .rel.iplt sections for STT_GNU_IFUNC symbols. */ - if (htab->elf.splt != NULL) - { - plt = htab->elf.splt; - gotplt = htab->elf.sgotplt; - relplt = htab->elf.srelplt; - - /* If this is the first .plt entry, make room for the special - first entry. */ - if (plt->size == 0) - plt->size += PLT_ENTRY_SIZE; - } - else - { - plt = htab->elf.iplt; - gotplt = htab->elf.igotplt; - relplt = htab->elf.irelplt; - } - - /* Don't update value of STT_GNU_IFUNC symbol to PLT. We need - the original value for R_386_IRELATIVE. */ - h->plt.offset = plt->size; - - /* Make room for this entry in the .plt/.iplt section. */ - plt->size += PLT_ENTRY_SIZE; - - /* We also need to make an entry in the .got.plt/.got.iplt - section, which will be placed in the .got section by the - linker script. */ - gotplt->size += 4; - - /* We also need to make an entry in the .rela.plt/.rela.iplt - section. */ - relplt->size += sizeof (Elf32_External_Rel); - relplt->reloc_count++; - - /* We need dynamic relocation for STT_GNU_IFUNC symbol only - when there is a non-GOT reference in a shared object. */ - if (!info->shared - || !h->non_got_ref) - eh->dyn_relocs = NULL; - - /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) - htab->elf.irelifunc->size += p->count * sizeof (Elf32_External_Rel); - - /* For STT_GNU_IFUNC symbol, .got.plt has the real function - addres 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 branch, it uses .got.plt. For symbol value, - 1. Use .got.plt in a shared object if it is forced local or - not dynamic. - 2. Use .got.plt in a non-shared object if pointer equality - isn't needed. - 3. Use .got.plt in PIE. - 4. Use .got.plt if .got isn't used. - 5. Otherwise use .got so that it can be shared among different - objects at run-time. - We only need to relocate .got entry in shared object. */ - if ((info->shared - && (h->dynindx == -1 - || h->forced_local)) - || (!info->shared - && !h->pointer_equality_needed) - || (info->executable && info->shared) - || htab->elf.sgot == NULL) - { - /* Use .got.plt. */ - h->got.offset = (bfd_vma) -1; - } - else - { - h->got.offset = htab->elf.sgot->size; - htab->elf.sgot->size += 4; - if (info->shared) - htab->elf.srelgot->size += sizeof (Elf32_External_Rel); - } - - return TRUE; - } + return _bfd_elf_allocate_ifunc_dyn_relocs (info, h, + &eh->dyn_relocs, + PLT_ENTRY_SIZE, 4); else if (htab->elf.dynamic_sections_created && h->plt.refcount > 0) { @@ -2337,7 +2178,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) should avoid writing assembly like ".long foo - .". */ if (SYMBOL_CALLS_LOCAL (info, h)) { - struct elf_i386_dyn_relocs **pp; + struct elf_dyn_relocs **pp; for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) { @@ -2352,7 +2193,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (htab->is_vxworks) { - struct elf_i386_dyn_relocs **pp; + struct elf_dyn_relocs **pp; for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) { if (strcmp (p->sec->output_section->name, ".tls_vars") == 0) @@ -2452,7 +2293,7 @@ static bfd_boolean elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) { struct elf_i386_link_hash_entry *eh; - struct elf_i386_dyn_relocs *p; + struct elf_dyn_relocs *p; if (h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; @@ -2522,9 +2363,9 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, for (s = ibfd->sections; s != NULL; s = s->next) { - struct elf_i386_dyn_relocs *p; + struct elf_dyn_relocs *p; - for (p = ((struct elf_i386_dyn_relocs *) + for (p = ((struct elf_dyn_relocs *) elf_section_data (s)->local_dynrel); p != NULL; p = p->next) diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 5947a3e82f..617832ab41 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -396,27 +396,6 @@ static const bfd_byte elf64_x86_64_plt_entry[PLT_ENTRY_SIZE] = 0, 0, 0, 0 /* replaced with offset to start of .plt0. */ }; -/* The x86-64 linker needs to keep track of the number of relocs that - it decides to copy as dynamic relocs in check_relocs for each symbol. - This is so that it can later discard them if they are found to be - unnecessary. We store the information in a field extending the - regular ELF linker hash table. */ - -struct elf64_x86_64_dyn_relocs -{ - /* Next section. */ - struct elf64_x86_64_dyn_relocs *next; - - /* The input section of the reloc. */ - asection *sec; - - /* Total number of relocs copied for the input section. */ - bfd_size_type count; - - /* Number of pc-relative relocs copied for the input section. */ - bfd_size_type pc_count; -}; - /* x86-64 ELF linker hash entry. */ struct elf64_x86_64_link_hash_entry @@ -424,7 +403,7 @@ struct elf64_x86_64_link_hash_entry struct elf_link_hash_entry elf; /* Track dynamic relocs copied for this symbol. */ - struct elf64_x86_64_dyn_relocs *dyn_relocs; + struct elf_dyn_relocs *dyn_relocs; #define GOT_UNKNOWN 0 #define GOT_NORMAL 1 @@ -726,14 +705,14 @@ elf64_x86_64_copy_indirect_symbol (struct bfd_link_info *info, { if (edir->dyn_relocs != NULL) { - struct elf64_x86_64_dyn_relocs **pp; - struct elf64_x86_64_dyn_relocs *p; + struct elf_dyn_relocs **pp; + struct elf_dyn_relocs *p; /* Add reloc counts against the indirect sym to the direct sym list. Merge any entries against the same section. */ for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) { - struct elf64_x86_64_dyn_relocs *q; + struct elf_dyn_relocs *q; for (q = edir->dyn_relocs; q != NULL; q = q->next) if (q->sec == p->sec) @@ -1192,41 +1171,14 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, h->pointer_equality_needed = 1; if (info->shared) { - struct elf64_x86_64_dyn_relocs *p; - struct elf64_x86_64_dyn_relocs **head; - /* We must copy these reloc types into the output file. Create a reloc section in dynobj and make room for this reloc. */ + sreloc = _bfd_elf_create_ifunc_dyn_reloc + (abfd, info, sec, sreloc, + &((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs); if (sreloc == NULL) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, htab->elf.dynobj, 3, abfd, TRUE); - - if (sreloc == NULL) - return FALSE; - } - - head = &((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs; - p = *head; - if (p == NULL || p->sec != sec) - { - bfd_size_type amt = sizeof *p; - - p = ((struct elf64_x86_64_dyn_relocs *) - bfd_alloc (htab->elf.dynobj, amt)); - if (p == NULL) - return FALSE; - p->next = *head; - *head = p; - p->sec = sec; - p->count = 0; - p->pc_count = 0; - } - p->count += 1; + return FALSE; } break; @@ -1500,8 +1452,8 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, && (h->root.type == bfd_link_hash_defweak || !h->def_regular))) { - struct elf64_x86_64_dyn_relocs *p; - struct elf64_x86_64_dyn_relocs **head; + struct elf_dyn_relocs *p; + struct elf_dyn_relocs **head; /* We must copy these reloc types into the output file. Create a reloc section in dynobj and make room for @@ -1540,7 +1492,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, /* Beware of type punned pointers vs strict aliasing rules. */ vpp = &(elf_section_data (s)->local_dynrel); - head = (struct elf64_x86_64_dyn_relocs **)vpp; + head = (struct elf_dyn_relocs **)vpp; } p = *head; @@ -1548,7 +1500,7 @@ elf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, { bfd_size_type amt = sizeof *p; - p = ((struct elf64_x86_64_dyn_relocs *) + p = ((struct elf_dyn_relocs *) bfd_alloc (htab->elf.dynobj, amt)); if (p == NULL) return FALSE; @@ -1642,8 +1594,8 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, if (r_symndx >= symtab_hdr->sh_info) { struct elf64_x86_64_link_hash_entry *eh; - struct elf64_x86_64_dyn_relocs **pp; - struct elf64_x86_64_dyn_relocs *p; + struct elf_dyn_relocs **pp; + struct elf_dyn_relocs *p; h = sym_hashes[r_symndx - symtab_hdr->sh_info]; while (h->root.type == bfd_link_hash_indirect @@ -1820,7 +1772,7 @@ elf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, if (ELIMINATE_COPY_RELOCS) { struct elf64_x86_64_link_hash_entry * eh; - struct elf64_x86_64_dyn_relocs *p; + struct elf_dyn_relocs *p; eh = (struct elf64_x86_64_link_hash_entry *) h; for (p = eh->dyn_relocs; p != NULL; p = p->next) @@ -1881,7 +1833,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) struct bfd_link_info *info; struct elf64_x86_64_link_hash_table *htab; struct elf64_x86_64_link_hash_entry *eh; - struct elf64_x86_64_dyn_relocs *p; + struct elf_dyn_relocs *p; if (h->root.type == bfd_link_hash_indirect) return TRUE; @@ -1897,124 +1849,10 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) here if it is defined and referenced in a non-shared object. */ if (h->type == STT_GNU_IFUNC && h->def_regular) - { - asection *plt, *gotplt, *relplt; - - /* When a shared library references a STT_GNU_IFUNC symbol - defined in executable, the address of the resolved function - may be used. But in non-shared executable, the address of - its .plt slot may be used. Pointer equality may not work - correctly. PIE should be used if pointer equality is - required here. */ - if (!info->shared - && (h->dynindx != -1 - || info->export_dynamic) - && h->pointer_equality_needed) - { - info->callbacks->einfo - (_("%F%P: dynamic STT_GNU_IFUNC symbol `%s' with pointer " - "equality in `%B' 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 and discard space for dynamic relocations against it if - it is never referenced in a non-shared object. */ - if (!h->ref_regular) - { - if (h->plt.refcount > 0 - || h->got.refcount > 0) - abort (); - h->got.offset = (bfd_vma) -1; - eh->dyn_relocs = NULL; - return TRUE; - } - - /* When building a static executable, use .iplt, .igot.plt and - .rela.iplt sections for STT_GNU_IFUNC symbols. */ - if (htab->elf.splt != NULL) - { - plt = htab->elf.splt; - gotplt = htab->elf.sgotplt; - relplt = htab->elf.srelplt; - - /* If this is the first .plt entry, make room for the special - first entry. */ - if (plt->size == 0) - plt->size += PLT_ENTRY_SIZE; - } - else - { - plt = htab->elf.iplt; - gotplt = htab->elf.igotplt; - relplt = htab->elf.irelplt; - } - - /* Don't update value of STT_GNU_IFUNC symbol to PLT. We need - the original value for R_X86_64_IRELATIVE. */ - h->plt.offset = plt->size; - - /* Make room for this entry in the .plt/.iplt section. */ - plt->size += PLT_ENTRY_SIZE; - - /* We also need to make an entry in the .got.plt/.got.iplt - section, which will be placed in the .got section by the - linker script. */ - gotplt->size += GOT_ENTRY_SIZE; - - /* We also need to make an entry in the .rela.plt/.rela.iplt - section. */ - relplt->size += sizeof (Elf64_External_Rela); - relplt->reloc_count++; - - /* We need dynamic relocation for STT_GNU_IFUNC symbol only - when there is a non-GOT reference in a shared object. */ - if (!info->shared - || !h->non_got_ref) - eh->dyn_relocs = NULL; - - /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) - htab->elf.irelifunc->size - += p->count * sizeof (Elf64_External_Rela); - - /* For STT_GNU_IFUNC symbol, .got.plt has the real function - addres 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 branch, it uses .got.plt. For symbol value, - 1. Use .got.plt in a shared object if it is forced local or - not dynamic. - 2. Use .got.plt in a non-shared object if pointer equality - isn't needed. - 3. Use .got.plt in PIE. - 4. Use .got.plt if .got isn't used. - 5. Otherwise use .got so that it can be shared among different - objects at run-time. - We only need to relocate .got entry in shared object. */ - if ((info->shared - && (h->dynindx == -1 - || h->forced_local)) - || (!info->shared - && !h->pointer_equality_needed) - || (info->executable && info->shared) - || htab->elf.sgot == NULL) - { - /* Use .got.plt. */ - h->got.offset = (bfd_vma) -1; - } - else - { - h->got.offset = htab->elf.sgot->size; - htab->elf.sgot->size += GOT_ENTRY_SIZE; - if (info->shared) - htab->elf.srelgot->size += sizeof (Elf64_External_Rela); - } - - return TRUE; - } + return _bfd_elf_allocate_ifunc_dyn_relocs (info, h, + &eh->dyn_relocs, + PLT_ENTRY_SIZE, + GOT_ENTRY_SIZE); else if (htab->elf.dynamic_sections_created && h->plt.refcount > 0) { @@ -2159,7 +1997,7 @@ elf64_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) should avoid writing weird assembly. */ if (SYMBOL_CALLS_LOCAL (info, h)) { - struct elf64_x86_64_dyn_relocs **pp; + struct elf_dyn_relocs **pp; for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) { @@ -2260,7 +2098,7 @@ static bfd_boolean elf64_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h, void * inf) { struct elf64_x86_64_link_hash_entry *eh; - struct elf64_x86_64_dyn_relocs *p; + struct elf_dyn_relocs *p; if (h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; @@ -2330,9 +2168,9 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, for (s = ibfd->sections; s != NULL; s = s->next) { - struct elf64_x86_64_dyn_relocs *p; + struct elf_dyn_relocs *p; - for (p = (struct elf64_x86_64_dyn_relocs *) + for (p = (struct elf_dyn_relocs *) (elf_section_data (s)->local_dynrel); p != NULL; p = p->next)