From 3d13f3e9bda5aada68915f5d958f731ae79ed41d Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Tue, 19 Sep 2017 11:59:30 +0930 Subject: [PATCH] PR22150, ld keeps a version reference for gc'd symbols elf_gc_sweep_symbol should run after verdefs are calculated, since the verdef code creates symbols for the versions. However, elf_gc_sweep_symbol needs to run before verrefs so as to not emit useless verrefs for symbols that are gc'd. I've also removed a _bfd_elf_link_renumber_dynsyms calls added by Maciej after I fussed about it when reviewing. On further examination the call appears to be unnecessary. Looking at renumber_dynsyms also made me realize that the test to exclude .gnu.version has been wrong since 2016-04-26 (git commit d5486c4372), so fix that too. PR 22150 * elflink.c (bfd_elf_size_dynamic_sections): Garbage collect symbols before calculating verrefs. Don't renumber dynsyms after gc. Exclude .gnu.version when zero or one dynsym. Localize some vars and reindent. --- bfd/ChangeLog | 8 ++ bfd/elflink.c | 227 ++++++++++++++++++++++++-------------------------- 2 files changed, 118 insertions(+), 117 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index c6075498d3f..eb62bc3b273 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,11 @@ +2017-09-19 Alan Modra + + PR 22150 + * elflink.c (bfd_elf_size_dynamic_sections): Garbage collect + symbols before calculating verrefs. Don't renumber dynsyms + after gc. Exclude .gnu.version when zero or one dynsym. + Localize some vars and reindent. + 2017-09-18 H.J. Lu PR ld/22148 diff --git a/bfd/elflink.c b/bfd/elflink.c index 58fb83b4b27..ee5c01fde78 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -6006,19 +6006,18 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, struct elf_info_failed asvinfo; struct bfd_elf_version_tree *t; struct bfd_elf_version_expr *d; - struct elf_info_failed eif; - bfd_boolean all_defined; asection *s; size_t soname_indx; - eif.info = info; - eif.failed = FALSE; - /* If we are supposed to export all symbols into the dynamic symbol table (this is not the normal case), then do so. */ if (info->export_dynamic || (bfd_link_executable (info) && info->dynamic)) { + struct elf_info_failed eif; + + eif.info = info; + eif.failed = FALSE; elf_link_hash_traverse (elf_hash_table (info), _bfd_elf_export_symbol, &eif); @@ -6102,7 +6101,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, if (!info->allow_undefined_version) { /* Check if all global versions have a definition. */ - all_defined = TRUE; + bfd_boolean all_defined = TRUE; for (t = info->version_info; t != NULL; t = t->next) for (d = t->globals.list; d != NULL; d = d->next) if (d->literal && !d->symver && !d->script) @@ -6355,134 +6354,128 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, elf_tdata (output_bfd)->cverdefs = cdefs; } + } + + bed = get_elf_backend_data (output_bfd); + + if (info->gc_sections && bed->can_gc_sections) + { + struct elf_gc_sweep_symbol_info sweep_info; + + /* Remove the symbols that were in the swept sections from the + dynamic symbol table. */ + sweep_info.info = info; + sweep_info.hide_symbol = bed->elf_backend_hide_symbol; + elf_link_hash_traverse (elf_hash_table (info), elf_gc_sweep_symbol, + &sweep_info); + } + + if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created) + { + asection *s; + struct elf_find_verdep_info sinfo; /* Work out the size of the version reference section. */ s = bfd_get_linker_section (dynobj, ".gnu.version_r"); BFD_ASSERT (s != NULL); - { - struct elf_find_verdep_info sinfo; - - sinfo.info = info; - sinfo.vers = elf_tdata (output_bfd)->cverdefs; - if (sinfo.vers == 0) - sinfo.vers = 1; - sinfo.failed = FALSE; - elf_link_hash_traverse (elf_hash_table (info), - _bfd_elf_link_find_version_dependencies, - &sinfo); - if (sinfo.failed) - return FALSE; + sinfo.info = info; + sinfo.vers = elf_tdata (output_bfd)->cverdefs; + if (sinfo.vers == 0) + sinfo.vers = 1; + sinfo.failed = FALSE; - if (elf_tdata (output_bfd)->verref == NULL) - s->flags |= SEC_EXCLUDE; - else - { - Elf_Internal_Verneed *vn; - unsigned int size; - unsigned int crefs; - bfd_byte *p; - - /* Build the version dependency section. */ - size = 0; - crefs = 0; - for (vn = elf_tdata (output_bfd)->verref; - vn != NULL; - vn = vn->vn_nextref) - { - Elf_Internal_Vernaux *a; + elf_link_hash_traverse (elf_hash_table (info), + _bfd_elf_link_find_version_dependencies, + &sinfo); + if (sinfo.failed) + return FALSE; - size += sizeof (Elf_External_Verneed); - ++crefs; - for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr) - size += sizeof (Elf_External_Vernaux); - } + if (elf_tdata (output_bfd)->verref == NULL) + s->flags |= SEC_EXCLUDE; + else + { + Elf_Internal_Verneed *vn; + unsigned int size; + unsigned int crefs; + bfd_byte *p; - s->size = size; - s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size); - if (s->contents == NULL) - return FALSE; + /* Build the version dependency section. */ + size = 0; + crefs = 0; + for (vn = elf_tdata (output_bfd)->verref; + vn != NULL; + vn = vn->vn_nextref) + { + Elf_Internal_Vernaux *a; - p = s->contents; - for (vn = elf_tdata (output_bfd)->verref; - vn != NULL; - vn = vn->vn_nextref) - { - unsigned int caux; - Elf_Internal_Vernaux *a; - size_t indx; - - caux = 0; - for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr) - ++caux; - - vn->vn_version = VER_NEED_CURRENT; - vn->vn_cnt = caux; - indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, - elf_dt_name (vn->vn_bfd) != NULL - ? elf_dt_name (vn->vn_bfd) - : lbasename (vn->vn_bfd->filename), - FALSE); - if (indx == (size_t) -1) - return FALSE; - vn->vn_file = indx; - vn->vn_aux = sizeof (Elf_External_Verneed); - if (vn->vn_nextref == NULL) - vn->vn_next = 0; - else - vn->vn_next = (sizeof (Elf_External_Verneed) - + caux * sizeof (Elf_External_Vernaux)); + size += sizeof (Elf_External_Verneed); + ++crefs; + for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr) + size += sizeof (Elf_External_Vernaux); + } - _bfd_elf_swap_verneed_out (output_bfd, vn, - (Elf_External_Verneed *) p); - p += sizeof (Elf_External_Verneed); + s->size = size; + s->contents = (unsigned char *) bfd_alloc (output_bfd, s->size); + if (s->contents == NULL) + return FALSE; - for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr) - { - a->vna_hash = bfd_elf_hash (a->vna_nodename); - indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, - a->vna_nodename, FALSE); - if (indx == (size_t) -1) - return FALSE; - a->vna_name = indx; - if (a->vna_nextptr == NULL) - a->vna_next = 0; - else - a->vna_next = sizeof (Elf_External_Vernaux); + p = s->contents; + for (vn = elf_tdata (output_bfd)->verref; + vn != NULL; + vn = vn->vn_nextref) + { + unsigned int caux; + Elf_Internal_Vernaux *a; + size_t indx; - _bfd_elf_swap_vernaux_out (output_bfd, a, - (Elf_External_Vernaux *) p); - p += sizeof (Elf_External_Vernaux); - } - } + caux = 0; + for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr) + ++caux; - elf_tdata (output_bfd)->cverrefs = crefs; - } - } - } + vn->vn_version = VER_NEED_CURRENT; + vn->vn_cnt = caux; + indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, + elf_dt_name (vn->vn_bfd) != NULL + ? elf_dt_name (vn->vn_bfd) + : lbasename (vn->vn_bfd->filename), + FALSE); + if (indx == (size_t) -1) + return FALSE; + vn->vn_file = indx; + vn->vn_aux = sizeof (Elf_External_Verneed); + if (vn->vn_nextref == NULL) + vn->vn_next = 0; + else + vn->vn_next = (sizeof (Elf_External_Verneed) + + caux * sizeof (Elf_External_Vernaux)); - bed = get_elf_backend_data (output_bfd); + _bfd_elf_swap_verneed_out (output_bfd, vn, + (Elf_External_Verneed *) p); + p += sizeof (Elf_External_Verneed); - if (info->gc_sections && bed->can_gc_sections) - { - struct elf_gc_sweep_symbol_info sweep_info; - unsigned long section_sym_count; + for (a = vn->vn_auxptr; a != NULL; a = a->vna_nextptr) + { + a->vna_hash = bfd_elf_hash (a->vna_nodename); + indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, + a->vna_nodename, FALSE); + if (indx == (size_t) -1) + return FALSE; + a->vna_name = indx; + if (a->vna_nextptr == NULL) + a->vna_next = 0; + else + a->vna_next = sizeof (Elf_External_Vernaux); - /* Remove the symbols that were in the swept sections from the - dynamic symbol table. GCFIXME: Anyone know how to get them - out of the static symbol table as well? */ - sweep_info.info = info; - sweep_info.hide_symbol = bed->elf_backend_hide_symbol; - elf_link_hash_traverse (elf_hash_table (info), elf_gc_sweep_symbol, - &sweep_info); + _bfd_elf_swap_vernaux_out (output_bfd, a, + (Elf_External_Vernaux *) p); + p += sizeof (Elf_External_Vernaux); + } + } - /* We need to reassign dynsym indices now that symbols may have - been removed. See the call in `bfd_elf_size_dynsym_hash_dynstr' - for the details of the conditions used here. */ - if (elf_hash_table (info)->dynamic_sections_created - || bed->always_renumber_dynsyms) - _bfd_elf_link_renumber_dynsyms (output_bfd, info, §ion_sym_count); + elf_tdata (output_bfd)->cverrefs = crefs; + } } /* Any syms created from now on start with -1 in @@ -6792,7 +6785,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, if ((elf_tdata (output_bfd)->cverrefs == 0 && elf_tdata (output_bfd)->cverdefs == 0) || _bfd_elf_link_renumber_dynsyms (output_bfd, info, - §ion_sym_count) == 0) + §ion_sym_count) <= 1) { asection *s; -- 2.30.2