From b9ce864ca8dcd0e52e2b7c655603b181fa19cfbf Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Sat, 2 Sep 2017 07:26:54 -0700 Subject: [PATCH] x86: Add _bfd_x86_elf_allocate_dynrelocs Share _bfd_x86_elf_allocate_dynrelocs in elf32-i386.c and elf64-x86-64.c. * elf32-i386.c (elf_i386_allocate_dynrelocs): Removed. (elf_i386_allocate_local_dynrelocs): Likewise. (elf_i386_size_dynamic_sections): Replace elf_i386_allocate_dynrelocs/elf_i386_allocate_local_dynrelocs with _bfd_x86_elf_allocate_dynrelocs and _bfd_x86_elf_allocate_local_dynrelocs. * elf64-x86-64.c (elf_x86_64_allocate_dynrelocs): Removed. (elf_x86_64_allocate_local_dynrelocs): Likewise. (elf_x86_64_size_dynamic_sections): Replace elf_x86_64_allocate_dynrelocs/elf_x86_64_allocate_local_dynrelocs with _bfd_x86_elf_allocate_dynrelocs and _bfd_x86_elf_allocate_local_dynrelocs. * elfxx-x86.c (_bfd_x86_elf_allocate_dynrelocs): New function. (_bfd_x86_elf_allocate_local_dynrelocs): Likewise. * elfxx-x86.h (_bfd_x86_elf_allocate_dynrelocs): New prototype. (_bfd_x86_elf_allocate_local_dynrelocs): Likewise. --- bfd/ChangeLog | 19 ++ bfd/elf32-i386.c | 455 +------------------------------------------ bfd/elf64-x86-64.c | 412 +-------------------------------------- bfd/elfxx-x86.c | 472 +++++++++++++++++++++++++++++++++++++++++++++ bfd/elfxx-x86.h | 6 + 5 files changed, 502 insertions(+), 862 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 5830e42b0f3..4d6fb59560e 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,22 @@ +2017-09-02 H.J. Lu + + * elf32-i386.c (elf_i386_allocate_dynrelocs): Removed. + (elf_i386_allocate_local_dynrelocs): Likewise. + (elf_i386_size_dynamic_sections): Replace + elf_i386_allocate_dynrelocs/elf_i386_allocate_local_dynrelocs + with _bfd_x86_elf_allocate_dynrelocs and + _bfd_x86_elf_allocate_local_dynrelocs. + * elf64-x86-64.c (elf_x86_64_allocate_dynrelocs): Removed. + (elf_x86_64_allocate_local_dynrelocs): Likewise. + (elf_x86_64_size_dynamic_sections): Replace + elf_x86_64_allocate_dynrelocs/elf_x86_64_allocate_local_dynrelocs + with _bfd_x86_elf_allocate_dynrelocs and + _bfd_x86_elf_allocate_local_dynrelocs. + * elfxx-x86.c (_bfd_x86_elf_allocate_dynrelocs): New function. + (_bfd_x86_elf_allocate_local_dynrelocs): Likewise. + * elfxx-x86.h (_bfd_x86_elf_allocate_dynrelocs): New prototype. + (_bfd_x86_elf_allocate_local_dynrelocs): Likewise. + 2017-09-02 H.J. Lu * elf32-i386.c (is_i386_elf): Removed. diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index bc2b2191f4f..2caff7f96b8 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -1951,456 +1951,6 @@ error_return: return FALSE; } -/* Allocate space in .plt, .got and associated reloc sections for - dynamic relocs. */ - -static bfd_boolean -elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) -{ - struct bfd_link_info *info; - struct elf_x86_link_hash_table *htab; - struct elf_x86_link_hash_entry *eh; - struct elf_dyn_relocs *p; - unsigned plt_entry_size; - bfd_boolean resolved_to_zero; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - eh = (struct elf_x86_link_hash_entry *) h; - - info = (struct bfd_link_info *) inf; - htab = elf_x86_hash_table (info, I386_ELF_DATA); - if (htab == NULL) - return FALSE; - - plt_entry_size = htab->plt.plt_entry_size; - - resolved_to_zero = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, - I386_ELF_DATA, - eh->has_got_reloc, - eh); - - /* Clear the reference count of function pointer relocations if - symbol isn't a normal function. */ - if (h->type != STT_FUNC) - eh->func_pointer_refcount = 0; - - /* We can't use the GOT PLT if pointer equality is needed since - finish_dynamic_symbol won't clear symbol value and the dynamic - linker won't update the GOT slot. We will get into an infinite - loop at run-time. */ - if (htab->plt_got != NULL - && h->type != STT_GNU_IFUNC - && !h->pointer_equality_needed - && h->plt.refcount > 0 - && h->got.refcount > 0) - { - /* Don't use the regular PLT if there are both GOT and GOTPLT - reloctions. */ - h->plt.offset = (bfd_vma) -1; - - /* Use the GOT PLT. */ - eh->plt_got.refcount = 1; - } - - /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it - here if it is defined and referenced in a non-shared object. */ - if (h->type == STT_GNU_IFUNC - && h->def_regular) - { - if (_bfd_elf_allocate_ifunc_dyn_relocs (info, h, &eh->dyn_relocs, - &htab->readonly_dynrelocs_against_ifunc, - plt_entry_size, - (htab->plt.has_plt0 - * plt_entry_size), - 4, TRUE)) - { - asection *s = htab->plt_second; - if (h->plt.offset != (bfd_vma) -1 && s != NULL) - { - /* Use the second PLT section if it is created. */ - eh->plt_second.offset = s->size; - - /* Make room for this entry in the second PLT section. */ - s->size += htab->non_lazy_plt->plt_entry_size; - } - - return TRUE; - } - else - return FALSE; - } - /* Don't create the PLT entry if there are only function pointer - relocations which can be resolved at run-time. */ - else if (htab->elf.dynamic_sections_created - && (h->plt.refcount > eh->func_pointer_refcount - || eh->plt_got.refcount > 0)) - { - bfd_boolean use_plt_got = eh->plt_got.refcount > 0; - - /* Clear the reference count of function pointer relocations - if PLT is used. */ - eh->func_pointer_refcount = 0; - - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local - && !resolved_to_zero - && h->root.type == bfd_link_hash_undefweak) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - if (bfd_link_pic (info) - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) - { - asection *s = htab->elf.splt; - asection *second_s = htab->plt_second; - asection *got_s = htab->plt_got; - - /* If this is the first .plt entry, make room for the special - first entry. The .plt section is used by prelink to undo - prelinking for dynamic relocations. */ - if (s->size == 0) - s->size = htab->plt.has_plt0 * plt_entry_size; - - if (use_plt_got) - eh->plt_got.offset = got_s->size; - else - { - h->plt.offset = s->size; - if (second_s) - eh->plt_second.offset = second_s->size; - } - - /* If this symbol is not defined in a regular file, and we are - not generating a shared library, then set the symbol to this - location in the .plt. This is required to make function - pointers compare as equal between the normal executable and - the shared library. */ - if (! bfd_link_pic (info) - && !h->def_regular) - { - if (use_plt_got) - { - /* We need to make a call to the entry of the GOT PLT - instead of regular PLT entry. */ - h->root.u.def.section = got_s; - h->root.u.def.value = eh->plt_got.offset; - } - else - { - if (second_s) - { - /* We need to make a call to the entry of the - second PLT instead of regular PLT entry. */ - h->root.u.def.section = second_s; - h->root.u.def.value = eh->plt_second.offset; - } - else - { - h->root.u.def.section = s; - h->root.u.def.value = h->plt.offset; - } - } - } - - /* Make room for this entry. */ - if (use_plt_got) - got_s->size += htab->non_lazy_plt->plt_entry_size; - else - { - s->size += plt_entry_size; - if (second_s) - second_s->size += htab->non_lazy_plt->plt_entry_size; - - /* We also need to make an entry in the .got.plt section, - which will be placed in the .got section by the linker - script. */ - htab->elf.sgotplt->size += 4; - - /* There should be no PLT relocation against resolved - undefined weak symbol in executable. */ - if (!resolved_to_zero) - { - /* We also need to make an entry in the .rel.plt - section. */ - htab->elf.srelplt->size += sizeof (Elf32_External_Rel); - htab->elf.srelplt->reloc_count++; - } - } - - if (htab->is_vxworks && !bfd_link_pic (info)) - { - /* VxWorks has a second set of relocations for each PLT entry - in executables. They go in a separate relocation section, - which is processed by the kernel loader. */ - - /* There are two relocations for the initial PLT entry: an - R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 4 and an - R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 8. */ - - asection *srelplt2 = htab->srelplt2; - if (h->plt.offset == plt_entry_size) - srelplt2->size += (sizeof (Elf32_External_Rel) * 2); - - /* There are two extra relocations for each subsequent PLT entry: - an R_386_32 relocation for the GOT entry, and an R_386_32 - relocation for the PLT entry. */ - - srelplt2->size += (sizeof (Elf32_External_Rel) * 2); - } - } - else - { - eh->plt_got.offset = (bfd_vma) -1; - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - } - else - { - eh->plt_got.offset = (bfd_vma) -1; - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - - eh->tlsdesc_got = (bfd_vma) -1; - - /* If R_386_TLS_{IE_32,IE,GOTIE} symbol is now local to the binary, - make it a R_386_TLS_LE_32 requiring no TLS entry. */ - if (h->got.refcount > 0 - && bfd_link_executable (info) - && h->dynindx == -1 - && (elf_x86_hash_entry (h)->tls_type & GOT_TLS_IE)) - h->got.offset = (bfd_vma) -1; - else if (h->got.refcount > 0) - { - asection *s; - bfd_boolean dyn; - int tls_type = elf_x86_hash_entry (h)->tls_type; - - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local - && !resolved_to_zero - && h->root.type == bfd_link_hash_undefweak) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - s = htab->elf.sgot; - if (GOT_TLS_GDESC_P (tls_type)) - { - eh->tlsdesc_got = htab->elf.sgotplt->size - - elf_x86_compute_jump_table_size (htab); - htab->elf.sgotplt->size += 8; - h->got.offset = (bfd_vma) -2; - } - if (! GOT_TLS_GDESC_P (tls_type) - || GOT_TLS_GD_P (tls_type)) - { - h->got.offset = s->size; - s->size += 4; - /* R_386_TLS_GD needs 2 consecutive GOT slots. */ - if (GOT_TLS_GD_P (tls_type) || tls_type == GOT_TLS_IE_BOTH) - s->size += 4; - } - dyn = htab->elf.dynamic_sections_created; - /* R_386_TLS_IE_32 needs one dynamic relocation, - R_386_TLS_IE resp. R_386_TLS_GOTIE needs one dynamic relocation, - (but if both R_386_TLS_IE_32 and R_386_TLS_IE is present, we - need two), R_386_TLS_GD needs one if local symbol and two if - global. No dynamic relocation against resolved undefined weak - symbol in executable. */ - if (tls_type == GOT_TLS_IE_BOTH) - htab->elf.srelgot->size += 2 * sizeof (Elf32_External_Rel); - else if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1) - || (tls_type & GOT_TLS_IE)) - htab->elf.srelgot->size += sizeof (Elf32_External_Rel); - else if (GOT_TLS_GD_P (tls_type)) - htab->elf.srelgot->size += 2 * sizeof (Elf32_External_Rel); - else if (! GOT_TLS_GDESC_P (tls_type) - && ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !resolved_to_zero) - || h->root.type != bfd_link_hash_undefweak) - && (bfd_link_pic (info) - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))) - htab->elf.srelgot->size += sizeof (Elf32_External_Rel); - if (GOT_TLS_GDESC_P (tls_type)) - htab->elf.srelplt->size += sizeof (Elf32_External_Rel); - } - else - h->got.offset = (bfd_vma) -1; - - if (eh->dyn_relocs == NULL) - return TRUE; - - /* In the shared -Bsymbolic case, discard space allocated for - dynamic pc-relative relocs against symbols which turn out to be - defined in regular objects. For the normal shared case, discard - space for pc-relative relocs that have become local due to symbol - visibility changes. */ - - if (bfd_link_pic (info)) - { - /* The only reloc that uses pc_count is R_386_PC32, which will - appear on a call or on something like ".long foo - .". We - want calls to protected symbols to resolve directly to the - function rather than going via the plt. If people want - function pointer comparisons to work as expected then they - should avoid writing assembly like ".long foo - .". */ - if (SYMBOL_CALLS_LOCAL (info, h)) - { - struct elf_dyn_relocs **pp; - - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) - { - p->count -= p->pc_count; - p->pc_count = 0; - if (p->count == 0) - *pp = p->next; - else - pp = &p->next; - } - } - - if (htab->is_vxworks) - { - struct elf_dyn_relocs **pp; - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) - { - if (strcmp (p->sec->output_section->name, ".tls_vars") == 0) - *pp = p->next; - else - pp = &p->next; - } - } - - /* Also discard relocs on undefined weak syms with non-default - visibility or in PIE. */ - if (eh->dyn_relocs != NULL - && h->root.type == bfd_link_hash_undefweak) - { - /* Undefined weak symbol is never bound locally in shared - library. */ - if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT - || resolved_to_zero) - { - if (h->non_got_ref) - { - /* Keep dynamic non-GOT/non-PLT relocation so that we - can branch to 0 without PLT. */ - struct elf_dyn_relocs **pp; - - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) - if (p->pc_count == 0) - *pp = p->next; - else - { - /* Remove non-R_386_PC32 relocation. */ - p->count = p->pc_count; - pp = &p->next; - } - - if (eh->dyn_relocs != NULL) - { - /* Make sure undefined weak symbols are output - as dynamic symbols in PIEs for dynamic non-GOT - non-PLT reloations. */ - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - } - else - eh->dyn_relocs = NULL; - } - else if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - } - } - else if (ELIMINATE_COPY_RELOCS) - { - /* For the non-shared case, discard space for relocs against - symbols which turn out to need copy relocs or are not - dynamic. Keep dynamic relocations for run-time function - pointer initialization. */ - - if ((!h->non_got_ref - || eh->func_pointer_refcount > 0 - || (h->root.type == bfd_link_hash_undefweak - && !resolved_to_zero)) - && ((h->def_dynamic - && !h->def_regular) - || (htab->elf.dynamic_sections_created - && (h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_undefined)))) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local - && !resolved_to_zero - && h->root.type == bfd_link_hash_undefweak) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - /* If that succeeded, we know we'll be keeping all the - relocs. */ - if (h->dynindx != -1) - goto keep; - } - - eh->dyn_relocs = NULL; - eh->func_pointer_refcount = 0; - - keep: ; - } - - /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection *sreloc; - - sreloc = elf_section_data (p->sec)->sreloc; - - BFD_ASSERT (sreloc != NULL); - sreloc->size += p->count * sizeof (Elf32_External_Rel); - } - - return TRUE; -} - -/* Allocate space in .plt, .got and associated reloc sections for - local dynamic relocs. */ - -static bfd_boolean -elf_i386_allocate_local_dynrelocs (void **slot, void *inf) -{ - struct elf_link_hash_entry *h - = (struct elf_link_hash_entry *) *slot; - - if (h->type != STT_GNU_IFUNC - || !h->def_regular - || !h->ref_regular - || !h->forced_local - || h->root.type != bfd_link_hash_defined) - abort (); - - return elf_i386_allocate_dynrelocs (h, inf); -} - /* Convert load via the GOT slot to load immediate. */ static bfd_boolean @@ -2673,11 +2223,12 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) /* Allocate global sym .plt and .got entries, and space for global sym dynamic relocs. */ - elf_link_hash_traverse (&htab->elf, elf_i386_allocate_dynrelocs, info); + elf_link_hash_traverse (&htab->elf, _bfd_x86_elf_allocate_dynrelocs, + info); /* Allocate .plt and .got entries, and space for local symbols. */ htab_traverse (htab->loc_hash_table, - elf_i386_allocate_local_dynrelocs, + _bfd_x86_elf_allocate_local_dynrelocs, info); /* For every jump slot reserved in the sgotplt, reloc_count is diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 7a6e1f1e829..ed67d89786c 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -2394,414 +2394,6 @@ error_return: return FALSE; } -/* Allocate space in .plt, .got and associated reloc sections for - dynamic relocs. */ - -static bfd_boolean -elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) -{ - struct bfd_link_info *info; - struct elf_x86_link_hash_table *htab; - struct elf_x86_link_hash_entry *eh; - struct elf_dyn_relocs *p; - const struct elf_backend_data *bed; - unsigned int plt_entry_size; - bfd_boolean resolved_to_zero; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - eh = (struct elf_x86_link_hash_entry *) h; - - info = (struct bfd_link_info *) inf; - htab = elf_x86_hash_table (info, X86_64_ELF_DATA); - if (htab == NULL) - return FALSE; - bed = get_elf_backend_data (info->output_bfd); - - plt_entry_size = htab->plt.plt_entry_size; - - resolved_to_zero = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, - X86_64_ELF_DATA, - eh->has_got_reloc, - eh); - - /* We can't use the GOT PLT if pointer equality is needed since - finish_dynamic_symbol won't clear symbol value and the dynamic - linker won't update the GOT slot. We will get into an infinite - loop at run-time. */ - if (htab->plt_got != NULL - && h->type != STT_GNU_IFUNC - && !h->pointer_equality_needed - && h->plt.refcount > 0 - && h->got.refcount > 0) - { - /* Don't use the regular PLT if there are both GOT and GOTPLT - reloctions. */ - h->plt.offset = (bfd_vma) -1; - - /* Use the GOT PLT. */ - eh->plt_got.refcount = 1; - } - - /* Clear the reference count of function pointer relocations if - symbol isn't a normal function. */ - if (h->type != STT_FUNC) - eh->func_pointer_refcount = 0; - - /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it - here if it is defined and referenced in a non-shared object. */ - if (h->type == STT_GNU_IFUNC - && h->def_regular) - { - if (_bfd_elf_allocate_ifunc_dyn_relocs (info, h, - &eh->dyn_relocs, - &htab->readonly_dynrelocs_against_ifunc, - plt_entry_size, - (htab->plt.has_plt0 - * plt_entry_size), - GOT_ENTRY_SIZE, TRUE)) - { - asection *s = htab->plt_second; - if (h->plt.offset != (bfd_vma) -1 && s != NULL) - { - /* Use the second PLT section if it is created. */ - eh->plt_second.offset = s->size; - - /* Make room for this entry in the second PLT section. */ - s->size += htab->non_lazy_plt->plt_entry_size; - } - - return TRUE; - } - else - return FALSE; - } - /* Don't create the PLT entry if there are only function pointer - relocations which can be resolved at run-time. */ - else if (htab->elf.dynamic_sections_created - && (h->plt.refcount > eh->func_pointer_refcount - || eh->plt_got.refcount > 0)) - { - bfd_boolean use_plt_got = eh->plt_got.refcount > 0; - - /* Clear the reference count of function pointer relocations - if PLT is used. */ - eh->func_pointer_refcount = 0; - - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local - && !resolved_to_zero - && h->root.type == bfd_link_hash_undefweak) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - if (bfd_link_pic (info) - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) - { - asection *s = htab->elf.splt; - asection *second_s = htab->plt_second; - asection *got_s = htab->plt_got; - - /* If this is the first .plt entry, make room for the special - first entry. The .plt section is used by prelink to undo - prelinking for dynamic relocations. */ - if (s->size == 0) - s->size = htab->plt.has_plt0 * plt_entry_size; - - if (use_plt_got) - eh->plt_got.offset = got_s->size; - else - { - h->plt.offset = s->size; - if (second_s) - eh->plt_second.offset = second_s->size; - } - - /* If this symbol is not defined in a regular file, and we are - not generating a shared library, then set the symbol to this - location in the .plt. This is required to make function - pointers compare as equal between the normal executable and - the shared library. */ - if (! bfd_link_pic (info) - && !h->def_regular) - { - if (use_plt_got) - { - /* We need to make a call to the entry of the GOT PLT - instead of regular PLT entry. */ - h->root.u.def.section = got_s; - h->root.u.def.value = eh->plt_got.offset; - } - else - { - if (second_s) - { - /* We need to make a call to the entry of the - second PLT instead of regular PLT entry. */ - h->root.u.def.section = second_s; - h->root.u.def.value = eh->plt_second.offset; - } - else - { - h->root.u.def.section = s; - h->root.u.def.value = h->plt.offset; - } - } - } - - /* Make room for this entry. */ - if (use_plt_got) - got_s->size += htab->non_lazy_plt->plt_entry_size; - else - { - s->size += plt_entry_size; - if (second_s) - second_s->size += htab->non_lazy_plt->plt_entry_size; - - /* We also need to make an entry in the .got.plt section, - which will be placed in the .got section by the linker - script. */ - htab->elf.sgotplt->size += GOT_ENTRY_SIZE; - - /* There should be no PLT relocation against resolved - undefined weak symbol in executable. */ - if (!resolved_to_zero) - { - /* We also need to make an entry in the .rela.plt - section. */ - htab->elf.srelplt->size += bed->s->sizeof_rela; - htab->elf.srelplt->reloc_count++; - } - } - } - else - { - eh->plt_got.offset = (bfd_vma) -1; - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - } - else - { - eh->plt_got.offset = (bfd_vma) -1; - h->plt.offset = (bfd_vma) -1; - h->needs_plt = 0; - } - - eh->tlsdesc_got = (bfd_vma) -1; - - /* If R_X86_64_GOTTPOFF symbol is now local to the binary, - make it a R_X86_64_TPOFF32 requiring no GOT entry. */ - if (h->got.refcount > 0 - && bfd_link_executable (info) - && h->dynindx == -1 - && elf_x86_hash_entry (h)->tls_type == GOT_TLS_IE) - { - h->got.offset = (bfd_vma) -1; - } - else if (h->got.refcount > 0) - { - asection *s; - bfd_boolean dyn; - int tls_type = elf_x86_hash_entry (h)->tls_type; - - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local - && !resolved_to_zero - && h->root.type == bfd_link_hash_undefweak) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - if (GOT_TLS_GDESC_P (tls_type)) - { - eh->tlsdesc_got = htab->elf.sgotplt->size - - elf_x86_compute_jump_table_size (htab); - htab->elf.sgotplt->size += 2 * GOT_ENTRY_SIZE; - h->got.offset = (bfd_vma) -2; - } - if (! GOT_TLS_GDESC_P (tls_type) - || GOT_TLS_GD_P (tls_type)) - { - s = htab->elf.sgot; - h->got.offset = s->size; - s->size += GOT_ENTRY_SIZE; - if (GOT_TLS_GD_P (tls_type)) - s->size += GOT_ENTRY_SIZE; - } - dyn = htab->elf.dynamic_sections_created; - /* R_X86_64_TLSGD needs one dynamic relocation if local symbol - and two if global. R_X86_64_GOTTPOFF needs one dynamic - relocation. No dynamic relocation against resolved undefined - weak symbol in executable. */ - if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1) - || tls_type == GOT_TLS_IE) - htab->elf.srelgot->size += bed->s->sizeof_rela; - else if (GOT_TLS_GD_P (tls_type)) - htab->elf.srelgot->size += 2 * bed->s->sizeof_rela; - else if (! GOT_TLS_GDESC_P (tls_type) - && ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - && !resolved_to_zero) - || h->root.type != bfd_link_hash_undefweak) - && (bfd_link_pic (info) - || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))) - htab->elf.srelgot->size += bed->s->sizeof_rela; - if (GOT_TLS_GDESC_P (tls_type)) - { - htab->elf.srelplt->size += bed->s->sizeof_rela; - htab->tlsdesc_plt = (bfd_vma) -1; - } - } - else - h->got.offset = (bfd_vma) -1; - - if (eh->dyn_relocs == NULL) - return TRUE; - - /* In the shared -Bsymbolic case, discard space allocated for - dynamic pc-relative relocs against symbols which turn out to be - defined in regular objects. For the normal shared case, discard - space for pc-relative relocs that have become local due to symbol - visibility changes. */ - - if (bfd_link_pic (info)) - { - /* Relocs that use pc_count are those that appear on a call - insn, or certain REL relocs that can generated via assembly. - We want calls to protected symbols to resolve directly to the - function rather than going via the plt. If people want - function pointer comparisons to work as expected then they - should avoid writing weird assembly. */ - if (SYMBOL_CALLS_LOCAL (info, h)) - { - struct elf_dyn_relocs **pp; - - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) - { - p->count -= p->pc_count; - p->pc_count = 0; - if (p->count == 0) - *pp = p->next; - else - pp = &p->next; - } - } - - /* Also discard relocs on undefined weak syms with non-default - visibility or in PIE. */ - if (eh->dyn_relocs != NULL) - { - if (h->root.type == bfd_link_hash_undefweak) - { - /* Undefined weak symbol is never bound locally in shared - library. */ - if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT - || resolved_to_zero) - eh->dyn_relocs = NULL; - else if (h->dynindx == -1 - && ! h->forced_local - && ! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - /* For PIE, discard space for pc-relative relocs against - symbols which turn out to need copy relocs. */ - else if (bfd_link_executable (info) - && (h->needs_copy || eh->needs_copy) - && h->def_dynamic - && !h->def_regular) - { - struct elf_dyn_relocs **pp; - - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) - { - if (p->pc_count != 0) - *pp = p->next; - else - pp = &p->next; - } - } - } - } - else if (ELIMINATE_COPY_RELOCS) - { - /* For the non-shared case, discard space for relocs against - symbols which turn out to need copy relocs or are not - dynamic. Keep dynamic relocations for run-time function - pointer initialization. */ - - if ((!h->non_got_ref - || eh->func_pointer_refcount > 0 - || (h->root.type == bfd_link_hash_undefweak - && !resolved_to_zero)) - && ((h->def_dynamic - && !h->def_regular) - || (htab->elf.dynamic_sections_created - && (h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_undefined)))) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && ! h->forced_local - && ! resolved_to_zero - && h->root.type == bfd_link_hash_undefweak - && ! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - - /* If that succeeded, we know we'll be keeping all the - relocs. */ - if (h->dynindx != -1) - goto keep; - } - - eh->dyn_relocs = NULL; - eh->func_pointer_refcount = 0; - - keep: ; - } - - /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection * sreloc; - - sreloc = elf_section_data (p->sec)->sreloc; - - BFD_ASSERT (sreloc != NULL); - - sreloc->size += p->count * bed->s->sizeof_rela; - } - - return TRUE; -} - -/* Allocate space in .plt, .got and associated reloc sections for - local dynamic relocs. */ - -static bfd_boolean -elf_x86_64_allocate_local_dynrelocs (void **slot, void *inf) -{ - struct elf_link_hash_entry *h - = (struct elf_link_hash_entry *) *slot; - - if (h->type != STT_GNU_IFUNC - || !h->def_regular - || !h->ref_regular - || !h->forced_local - || h->root.type != bfd_link_hash_defined) - abort (); - - return elf_x86_64_allocate_dynrelocs (h, inf); -} - /* Convert load via the GOT slot to load immediate. */ static bfd_boolean @@ -3072,12 +2664,12 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, /* Allocate global sym .plt and .got entries, and space for global sym dynamic relocs. */ - elf_link_hash_traverse (&htab->elf, elf_x86_64_allocate_dynrelocs, + elf_link_hash_traverse (&htab->elf, _bfd_x86_elf_allocate_dynrelocs, info); /* Allocate .plt and .got entries, and space for local symbols. */ htab_traverse (htab->loc_hash_table, - elf_x86_64_allocate_local_dynrelocs, + _bfd_x86_elf_allocate_local_dynrelocs, info); /* For every jump slot reserved in the sgotplt, reloc_count is diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c index b3d241cf360..646b2517874 100644 --- a/bfd/elfxx-x86.c +++ b/bfd/elfxx-x86.c @@ -79,6 +79,459 @@ _bfd_x86_elf_dtpoff_base (struct bfd_link_info *info) return elf_hash_table (info)->tls_sec->vma; } +/* Allocate space in .plt, .got and associated reloc sections for + dynamic relocs. */ + +bfd_boolean +_bfd_x86_elf_allocate_dynrelocs (struct elf_link_hash_entry *h, + void *inf) +{ + struct bfd_link_info *info; + struct elf_x86_link_hash_table *htab; + struct elf_x86_link_hash_entry *eh; + struct elf_dyn_relocs *p; + unsigned int plt_entry_size; + bfd_boolean resolved_to_zero; + const struct elf_backend_data *bed; + + if (h->root.type == bfd_link_hash_indirect) + return TRUE; + + eh = (struct elf_x86_link_hash_entry *) h; + + info = (struct bfd_link_info *) inf; + bed = get_elf_backend_data (info->output_bfd); + htab = elf_x86_hash_table (info, bed->target_id); + if (htab == NULL) + return FALSE; + + plt_entry_size = htab->plt.plt_entry_size; + + resolved_to_zero = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, + bed->target_id, + eh->has_got_reloc, + eh); + + /* Clear the reference count of function pointer relocations if + symbol isn't a normal function. */ + if (h->type != STT_FUNC) + eh->func_pointer_refcount = 0; + + /* We can't use the GOT PLT if pointer equality is needed since + finish_dynamic_symbol won't clear symbol value and the dynamic + linker won't update the GOT slot. We will get into an infinite + loop at run-time. */ + if (htab->plt_got != NULL + && h->type != STT_GNU_IFUNC + && !h->pointer_equality_needed + && h->plt.refcount > 0 + && h->got.refcount > 0) + { + /* Don't use the regular PLT if there are both GOT and GOTPLT + reloctions. */ + h->plt.offset = (bfd_vma) -1; + + /* Use the GOT PLT. */ + eh->plt_got.refcount = 1; + } + + /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it + here if it is defined and referenced in a non-shared object. */ + if (h->type == STT_GNU_IFUNC + && h->def_regular) + { + if (_bfd_elf_allocate_ifunc_dyn_relocs (info, h, &eh->dyn_relocs, + &htab->readonly_dynrelocs_against_ifunc, + plt_entry_size, + (htab->plt.has_plt0 + * plt_entry_size), + htab->got_entry_size, + TRUE)) + { + asection *s = htab->plt_second; + if (h->plt.offset != (bfd_vma) -1 && s != NULL) + { + /* Use the second PLT section if it is created. */ + eh->plt_second.offset = s->size; + + /* Make room for this entry in the second PLT section. */ + s->size += htab->non_lazy_plt->plt_entry_size; + } + + return TRUE; + } + else + return FALSE; + } + /* Don't create the PLT entry if there are only function pointer + relocations which can be resolved at run-time. */ + else if (htab->elf.dynamic_sections_created + && (h->plt.refcount > eh->func_pointer_refcount + || eh->plt_got.refcount > 0)) + { + bfd_boolean use_plt_got = eh->plt_got.refcount > 0; + + /* Clear the reference count of function pointer relocations + if PLT is used. */ + eh->func_pointer_refcount = 0; + + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && !h->forced_local + && !resolved_to_zero + && h->root.type == bfd_link_hash_undefweak) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + if (bfd_link_pic (info) + || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) + { + asection *s = htab->elf.splt; + asection *second_s = htab->plt_second; + asection *got_s = htab->plt_got; + + /* If this is the first .plt entry, make room for the special + first entry. The .plt section is used by prelink to undo + prelinking for dynamic relocations. */ + if (s->size == 0) + s->size = htab->plt.has_plt0 * plt_entry_size; + + if (use_plt_got) + eh->plt_got.offset = got_s->size; + else + { + h->plt.offset = s->size; + if (second_s) + eh->plt_second.offset = second_s->size; + } + + /* If this symbol is not defined in a regular file, and we are + not generating a shared library, then set the symbol to this + location in the .plt. This is required to make function + pointers compare as equal between the normal executable and + the shared library. */ + if (! bfd_link_pic (info) + && !h->def_regular) + { + if (use_plt_got) + { + /* We need to make a call to the entry of the GOT PLT + instead of regular PLT entry. */ + h->root.u.def.section = got_s; + h->root.u.def.value = eh->plt_got.offset; + } + else + { + if (second_s) + { + /* We need to make a call to the entry of the + second PLT instead of regular PLT entry. */ + h->root.u.def.section = second_s; + h->root.u.def.value = eh->plt_second.offset; + } + else + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } + } + } + + /* Make room for this entry. */ + if (use_plt_got) + got_s->size += htab->non_lazy_plt->plt_entry_size; + else + { + s->size += plt_entry_size; + if (second_s) + second_s->size += htab->non_lazy_plt->plt_entry_size; + + /* We also need to make an entry in the .got.plt section, + which will be placed in the .got section by the linker + script. */ + htab->elf.sgotplt->size += htab->got_entry_size; + + /* There should be no PLT relocation against resolved + undefined weak symbol in executable. */ + if (!resolved_to_zero) + { + /* We also need to make an entry in the .rel.plt + section. */ + htab->elf.srelplt->size += htab->sizeof_reloc; + htab->elf.srelplt->reloc_count++; + } + } + + if (htab->is_vxworks && !bfd_link_pic (info)) + { + /* VxWorks has a second set of relocations for each PLT entry + in executables. They go in a separate relocation section, + which is processed by the kernel loader. */ + + /* There are two relocations for the initial PLT entry: an + R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 4 and an + R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 8. */ + + asection *srelplt2 = htab->srelplt2; + if (h->plt.offset == plt_entry_size) + srelplt2->size += (htab->sizeof_reloc * 2); + + /* There are two extra relocations for each subsequent PLT entry: + an R_386_32 relocation for the GOT entry, and an R_386_32 + relocation for the PLT entry. */ + + srelplt2->size += (htab->sizeof_reloc * 2); + } + } + else + { + eh->plt_got.offset = (bfd_vma) -1; + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + } + else + { + eh->plt_got.offset = (bfd_vma) -1; + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + + eh->tlsdesc_got = (bfd_vma) -1; + + /* For i386, if R_386_TLS_{IE_32,IE,GOTIE} symbol is now local to the + binary, make it a R_386_TLS_LE_32 requiring no TLS entry. For + x86-64, if R_X86_64_GOTTPOFF symbol is now local to the binary, + make it a R_X86_64_TPOFF32 requiring no GOT entry. */ + if (h->got.refcount > 0 + && bfd_link_executable (info) + && h->dynindx == -1 + && (elf_x86_hash_entry (h)->tls_type & GOT_TLS_IE)) + h->got.offset = (bfd_vma) -1; + else if (h->got.refcount > 0) + { + asection *s; + bfd_boolean dyn; + int tls_type = elf_x86_hash_entry (h)->tls_type; + + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && !h->forced_local + && !resolved_to_zero + && h->root.type == bfd_link_hash_undefweak) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + s = htab->elf.sgot; + if (GOT_TLS_GDESC_P (tls_type)) + { + eh->tlsdesc_got = htab->elf.sgotplt->size + - elf_x86_compute_jump_table_size (htab); + htab->elf.sgotplt->size += 2 * htab->got_entry_size; + h->got.offset = (bfd_vma) -2; + } + if (! GOT_TLS_GDESC_P (tls_type) + || GOT_TLS_GD_P (tls_type)) + { + h->got.offset = s->size; + s->size += htab->got_entry_size; + /* R_386_TLS_GD and R_X86_64_TLSGD need 2 consecutive GOT + slots. */ + if (GOT_TLS_GD_P (tls_type) || tls_type == GOT_TLS_IE_BOTH) + s->size += htab->got_entry_size; + } + dyn = htab->elf.dynamic_sections_created; + /* R_386_TLS_IE_32 needs one dynamic relocation, + R_386_TLS_IE resp. R_386_TLS_GOTIE needs one dynamic relocation, + (but if both R_386_TLS_IE_32 and R_386_TLS_IE is present, we + need two), R_386_TLS_GD and R_X86_64_TLSGD need one if local + symbol and two if global. No dynamic relocation against + resolved undefined weak symbol in executable. */ + if (tls_type == GOT_TLS_IE_BOTH) + htab->elf.srelgot->size += 2 * htab->sizeof_reloc; + else if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1) + || (tls_type & GOT_TLS_IE)) + htab->elf.srelgot->size += htab->sizeof_reloc; + else if (GOT_TLS_GD_P (tls_type)) + htab->elf.srelgot->size += 2 * htab->sizeof_reloc; + else if (! GOT_TLS_GDESC_P (tls_type) + && ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + && !resolved_to_zero) + || h->root.type != bfd_link_hash_undefweak) + && (bfd_link_pic (info) + || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))) + htab->elf.srelgot->size += htab->sizeof_reloc; + if (GOT_TLS_GDESC_P (tls_type)) + htab->elf.srelplt->size += htab->sizeof_reloc; + } + else + h->got.offset = (bfd_vma) -1; + + if (eh->dyn_relocs == NULL) + return TRUE; + + /* In the shared -Bsymbolic case, discard space allocated for + dynamic pc-relative relocs against symbols which turn out to be + defined in regular objects. For the normal shared case, discard + space for pc-relative relocs that have become local due to symbol + visibility changes. */ + + if (bfd_link_pic (info)) + { + /* Relocs that use pc_count are those that appear on a call + insn, or certain REL relocs that can generated via assembly. + We want calls to protected symbols to resolve directly to the + function rather than going via the plt. If people want + function pointer comparisons to work as expected then they + should avoid writing weird assembly. */ + if (SYMBOL_CALLS_LOCAL (info, h)) + { + struct elf_dyn_relocs **pp; + + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + { + p->count -= p->pc_count; + p->pc_count = 0; + if (p->count == 0) + *pp = p->next; + else + pp = &p->next; + } + } + + if (htab->is_vxworks) + { + struct elf_dyn_relocs **pp; + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + { + if (strcmp (p->sec->output_section->name, ".tls_vars") == 0) + *pp = p->next; + else + pp = &p->next; + } + } + + /* Also discard relocs on undefined weak syms with non-default + visibility or in PIE. */ + if (eh->dyn_relocs != NULL) + { + if (h->root.type == bfd_link_hash_undefweak) + { + /* Undefined weak symbol is never bound locally in shared + library. */ + if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT + || resolved_to_zero) + { + if (bed->target_id == I386_ELF_DATA + && h->non_got_ref) + { + /* Keep dynamic non-GOT/non-PLT relocation so + that we can branch to 0 without PLT. */ + struct elf_dyn_relocs **pp; + + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + if (p->pc_count == 0) + *pp = p->next; + else + { + /* Remove non-R_386_PC32 relocation. */ + p->count = p->pc_count; + pp = &p->next; + } + + /* Make sure undefined weak symbols are output + as dynamic symbols in PIEs for dynamic non-GOT + non-PLT reloations. */ + if (eh->dyn_relocs != NULL + && !bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + else + eh->dyn_relocs = NULL; + } + else if (h->dynindx == -1 + && !h->forced_local + && !bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + else if (bfd_link_executable (info) + && (h->needs_copy || eh->needs_copy) + && h->def_dynamic + && !h->def_regular) + { + /* NB: needs_copy is set only for x86-64. For PIE, + discard space for pc-relative relocs against symbols + which turn out to need copy relocs. */ + struct elf_dyn_relocs **pp; + + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + { + if (p->pc_count != 0) + *pp = p->next; + else + pp = &p->next; + } + } + } + } + else if (ELIMINATE_COPY_RELOCS) + { + /* For the non-shared case, discard space for relocs against + symbols which turn out to need copy relocs or are not + dynamic. Keep dynamic relocations for run-time function + pointer initialization. */ + + if ((!h->non_got_ref + || eh->func_pointer_refcount > 0 + || (h->root.type == bfd_link_hash_undefweak + && !resolved_to_zero)) + && ((h->def_dynamic + && !h->def_regular) + || (htab->elf.dynamic_sections_created + && (h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined)))) + { + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && !h->forced_local + && !resolved_to_zero + && h->root.type == bfd_link_hash_undefweak + && ! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + + /* If that succeeded, we know we'll be keeping all the + relocs. */ + if (h->dynindx != -1) + goto keep; + } + + eh->dyn_relocs = NULL; + eh->func_pointer_refcount = 0; + + keep: ; + } + + /* Finally, allocate space. */ + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + asection *sreloc; + + sreloc = elf_section_data (p->sec)->sreloc; + + BFD_ASSERT (sreloc != NULL); + sreloc->size += p->count * htab->sizeof_reloc; + } + + return TRUE; +} + /* Find any dynamic relocs that apply to read-only sections. */ bfd_boolean @@ -117,6 +570,25 @@ _bfd_x86_elf_readonly_dynrelocs (struct elf_link_hash_entry *h, return TRUE; } +/* Allocate space in .plt, .got and associated reloc sections for + local dynamic relocs. */ + +bfd_boolean +_bfd_x86_elf_allocate_local_dynrelocs (void **slot, void *inf) +{ + struct elf_link_hash_entry *h + = (struct elf_link_hash_entry *) *slot; + + if (h->type != STT_GNU_IFUNC + || !h->def_regular + || !h->ref_regular + || !h->forced_local + || h->root.type != bfd_link_hash_defined) + abort (); + + return _bfd_x86_elf_allocate_dynrelocs (h, inf); +} + /* Find and/or create a hash entry for local symbol. */ struct elf_link_hash_entry * diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h index e3831357810..c694daf0fc5 100644 --- a/bfd/elfxx-x86.h +++ b/bfd/elfxx-x86.h @@ -401,6 +401,12 @@ extern void _bfd_x86_elf_set_tls_module_base extern bfd_vma _bfd_x86_elf_dtpoff_base (struct bfd_link_info *); +extern bfd_boolean _bfd_x86_elf_allocate_dynrelocs + (struct elf_link_hash_entry *, void *); + +extern bfd_boolean _bfd_x86_elf_allocate_local_dynrelocs + (void **, void *); + extern bfd_boolean _bfd_x86_elf_readonly_dynrelocs (struct elf_link_hash_entry *, void *); -- 2.30.2