From 5b677558bc6c7b2477bb33c709e6017e68e7ae8c Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 30 May 2016 09:43:44 +0930 Subject: [PATCH] Revert PR16467 change This reverts the pr16467 change, which was incorrect due to faulty analysis of the pr16467 testcase. The failure was not due to a mismatch in symbol type (ifunc/non-ifunc) but due to a symbol loop being set up. See https://sourceware.org/ml/binutils/2016-06/msg00013.html for some rambling on versioned symbols and ELF shared library symbol overriding that explain this patch. bfd/ PR ld/20159 PR ld/16467 * elflink.c (_bfd_elf_merge_symbol): Revert PR16467 change. (_bfd_elf_add_default_symbol): Don't indirect to/from defined symbol given a version by a script different to the version of the symbol being added. (elf_link_add_object_symbols): Use _bfd_elf_strtab_save and _bfd_elf_strtab_restore. Don't fudge dynstr references. * elf-strtab.c (_bfd_elf_strtab_restore_size): Delete. (struct strtab_save): New. (_bfd_elf_strtab_save, _bfd_elf_strtab_restore): New functions. * elf-bfd.h (_bfd_elf_strtab_restore_size): Delete. (_bfd_elf_strtab_save, _bfd_elf_strtab_restore): Declare. --- bfd/ChangeLog | 16 ++++++++++++++ bfd/elf-bfd.h | 8 ++++--- bfd/elf-strtab.c | 41 ++++++++++++++++++++++++++++++------ bfd/elflink.c | 63 +++++++++++++++++++++++++++++++++++++++----------------- 4 files changed, 100 insertions(+), 28 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 358b0db..0b6cd34 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,19 @@ +2016-05-31 Alan Modra + + PR ld/20159 + PR ld/16467 + * elflink.c (_bfd_elf_merge_symbol): Revert PR16467 change. + (_bfd_elf_add_default_symbol): Don't indirect to/from defined + symbol given a version by a script different to the version + of the symbol being added. + (elf_link_add_object_symbols): Use _bfd_elf_strtab_save and + _bfd_elf_strtab_restore. Don't fudge dynstr references. + * elf-strtab.c (_bfd_elf_strtab_restore_size): Delete. + (struct strtab_save): New. + (_bfd_elf_strtab_save, _bfd_elf_strtab_restore): New functions. + * elf-bfd.h (_bfd_elf_strtab_restore_size): Delete. + (_bfd_elf_strtab_save, _bfd_elf_strtab_restore): Declare. + 2016-06-01 Trevor Saunders * elf32-hppa.h: Add extern "C". diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 3184e57..99dbbce 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -2058,9 +2058,11 @@ extern void _bfd_elf_strtab_delref extern unsigned int _bfd_elf_strtab_refcount (struct elf_strtab_hash *, bfd_size_type); extern void _bfd_elf_strtab_clear_all_refs - (struct elf_strtab_hash *tab); -extern void _bfd_elf_strtab_restore_size - (struct elf_strtab_hash *, bfd_size_type); + (struct elf_strtab_hash *); +extern void *_bfd_elf_strtab_save + (struct elf_strtab_hash *); +extern void _bfd_elf_strtab_restore + (struct elf_strtab_hash *, void *); extern bfd_size_type _bfd_elf_strtab_size (struct elf_strtab_hash *); extern bfd_size_type _bfd_elf_strtab_offset diff --git a/bfd/elf-strtab.c b/bfd/elf-strtab.c index ca8ac33..19b0ad8 100644 --- a/bfd/elf-strtab.c +++ b/bfd/elf-strtab.c @@ -215,16 +215,45 @@ _bfd_elf_strtab_clear_all_refs (struct elf_strtab_hash *tab) tab->array[idx]->refcount = 0; } -/* Downsizes strtab. Entries from IDX up to the current size are - removed from the array. */ +/* Save strtab refcounts prior to adding --as-needed library. */ + +struct strtab_save +{ + bfd_size_type size; + unsigned int refcount[1]; +}; + +void * +_bfd_elf_strtab_save (struct elf_strtab_hash *tab) +{ + struct strtab_save *save; + bfd_size_type idx, size; + + size = sizeof (*save) + (tab->size - 1) * sizeof (save->refcount[0]); + save = bfd_malloc (size); + if (save == NULL) + return save; + + save->size = tab->size; + for (idx = 1; idx < tab->size; idx++) + save->refcount[idx] = tab->array[idx]->refcount; + return save; +} + +/* Restore strtab refcounts on finding --as-needed library not needed. */ + void -_bfd_elf_strtab_restore_size (struct elf_strtab_hash *tab, bfd_size_type idx) +_bfd_elf_strtab_restore (struct elf_strtab_hash *tab, void *buf) { - bfd_size_type curr_size = tab->size; + bfd_size_type idx, curr_size = tab->size; + struct strtab_save *save = (struct strtab_save *) buf; BFD_ASSERT (tab->sec_size == 0); - BFD_ASSERT (idx <= curr_size); - tab->size = idx; + BFD_ASSERT (save->size <= curr_size); + tab->size = save->size; + for (idx = 1; idx < save->size; ++idx) + tab->array[idx]->refcount = save->refcount[idx]; + for (; idx < curr_size; ++idx) { /* We don't remove entries from the hash table, just set their diff --git a/bfd/elflink.c b/bfd/elflink.c index 93e7dd2..8bb1066 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -1202,21 +1202,20 @@ _bfd_elf_merge_symbol (bfd *abfd, oldfunc = (h->type != STT_NOTYPE && bed->is_function_type (h->type)); - /* When we try to create a default indirect symbol from the dynamic - definition with the default version, we skip it if its type and - the type of existing regular definition mismatch. */ + /* If creating a default indirect symbol ("foo" or "foo@") from a + dynamic versioned definition ("foo@@") skip doing so if there is + an existing regular definition with a different type. We don't + want, for example, a "time" variable in the executable overriding + a "time" function in a shared library. */ if (pold_alignment == NULL && newdyn && newdef && !olddyn - && (((olddef || h->root.type == bfd_link_hash_common) - && ELF_ST_TYPE (sym->st_info) != h->type - && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE - && h->type != STT_NOTYPE - && !(newfunc && oldfunc)) - || (olddef - && ((h->type == STT_GNU_IFUNC) - != (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))))) + && (olddef || h->root.type == bfd_link_hash_common) + && ELF_ST_TYPE (sym->st_info) != h->type + && ELF_ST_TYPE (sym->st_info) != STT_NOTYPE + && h->type != STT_NOTYPE + && !(newfunc && oldfunc)) { *skip = TRUE; return TRUE; @@ -1781,6 +1780,31 @@ _bfd_elf_add_default_symbol (bfd *abfd, if (skip) goto nondefault; + if (hi->def_regular) + { + /* If the undecorated symbol will have a version added by a + script different to H, then don't indirect to/from the + undecorated symbol. This isn't ideal because we may not yet + have seen symbol versions, if given by a script on the + command line rather than via --version-script. */ + if (hi->verinfo.vertree == NULL && info->version_info != NULL) + { + bfd_boolean hide; + + hi->verinfo.vertree + = bfd_find_version_for_sym (info->version_info, + hi->root.root.string, &hide); + if (hi->verinfo.vertree != NULL && hide) + { + (*bed->elf_backend_hide_symbol) (info, hi, TRUE); + goto nondefault; + } + } + if (hi->verinfo.vertree != NULL + && strcmp (p + 1 + (p[1] == '@'), hi->verinfo.vertree->name) != 0) + goto nondefault; + } + if (! override) { /* Add the default symbol if not performing a relocatable link. */ @@ -3591,8 +3615,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) void *old_ent; struct bfd_link_hash_entry *old_undefs = NULL; struct bfd_link_hash_entry *old_undefs_tail = NULL; - long old_dynsymcount = 0; - bfd_size_type old_dynstr_size = 0; + void *old_strtab = NULL; size_t tabsize = 0; asection *s; bfd_boolean just_syms; @@ -4036,8 +4059,9 @@ error_free_dyn: old_table = htab->root.table.table; old_size = htab->root.table.size; old_count = htab->root.table.count; - old_dynsymcount = htab->dynsymcount; - old_dynstr_size = _bfd_elf_strtab_size (htab->dynstr); + old_strtab = _bfd_elf_strtab_save (htab->dynstr); + if (old_strtab == NULL) + goto error_free_vers; for (i = 0; i < htab->root.table.size; i++) { @@ -4762,7 +4786,9 @@ error_free_dyn: memcpy (htab->root.table.table, old_tab, tabsize); htab->root.undefs = old_undefs; htab->root.undefs_tail = old_undefs_tail; - _bfd_elf_strtab_restore_size (htab->dynstr, old_dynstr_size); + _bfd_elf_strtab_restore (htab->dynstr, old_strtab); + free (old_strtab); + old_strtab = NULL; for (i = 0; i < htab->root.table.size; i++) { struct bfd_hash_entry *p; @@ -4775,9 +4801,6 @@ error_free_dyn: h = (struct elf_link_hash_entry *) p; if (h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; - if (h->dynindx >= old_dynsymcount - && h->dynstr_index < old_dynstr_size) - _bfd_elf_strtab_delref (htab->dynstr, h->dynstr_index); /* Preserve the maximum alignment and size for common symbols even if this dynamic lib isn't on DT_NEEDED @@ -5099,6 +5122,8 @@ error_free_dyn: error_free_vers: if (old_tab != NULL) free (old_tab); + if (old_strtab != NULL) + free (old_strtab); if (nondeflt_vers != NULL) free (nondeflt_vers); if (extversym != NULL) -- 2.7.4