diff --git a/bfd/ChangeLog b/bfd/ChangeLog index b3bcf9ea1e..fa29df2267 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,15 @@ +2020-12-04 Alan Modra + + PR 26978 + * elflink.c (_bfd_elf_add_default_symbol): Handle the case where + a new weak sym@@ver should be overridden by an existing sym@ver. + (elf_link_add_object_symbols): Don't _bfd_elf_add_default_symbol + for a new weak sym@ver when sym@@ver already exists. + * linker.c (link_action): Choose MIND for previous indirect, + current def, rather than MDEF. + (_bfd_generic_link_add_one_symbol ): Handle redefinition of + weak indirect symbol. + 2020-12-01 Nelson Chu * elfxx-riscv.c (riscv_parse_prefixed_ext): Use riscv_compare_subsets diff --git a/bfd/elflink.c b/bfd/elflink.c index 512c5044b3..29b46f1568 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -2078,9 +2078,26 @@ _bfd_elf_add_default_symbol (bfd *abfd, return FALSE; if (skip) - return TRUE; - - if (override) + { + if (!dynamic + && h->root.type == bfd_link_hash_defweak + && hi->root.type == bfd_link_hash_defined) + { + /* We are handling a weak sym@@ver and attempting to define + a weak sym@ver, but _bfd_elf_merge_symbol said to skip the + new weak sym@ver because there is already a strong sym@ver. + However, sym@ver and sym@@ver are really the same symbol. + The existing strong sym@ver ought to override sym@@ver. */ + h->root.type = bfd_link_hash_defined; + h->root.u.def.section = hi->root.u.def.section; + h->root.u.def.value = hi->root.u.def.value; + hi->root.type = bfd_link_hash_indirect; + hi->root.u.i.link = &h->root; + } + else + return TRUE; + } + else if (override) { /* Here SHORTNAME is a versioned name, so we don't expect to see the type of override we do in the case above unless it is @@ -2091,6 +2108,7 @@ _bfd_elf_add_default_symbol (bfd *abfd, /* xgettext:c-format */ (_("%pB: unexpected redefinition of indirect versioned symbol `%s'"), abfd, shortname); + return TRUE; } else { @@ -2100,37 +2118,36 @@ _bfd_elf_add_default_symbol (bfd *abfd, bfd_ind_section_ptr, 0, name, FALSE, collect, &bh))) return FALSE; hi = (struct elf_link_hash_entry *) bh; + } - /* If there is a duplicate definition somewhere, then HI may not - point to an indirect symbol. We will have reported an error - to the user in that case. */ + /* If there is a duplicate definition somewhere, then HI may not + point to an indirect symbol. We will have reported an error + to the user in that case. */ + if (hi->root.type == bfd_link_hash_indirect) + { + (*bed->elf_backend_copy_indirect_symbol) (info, h, hi); + h->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak; + hi->dynamic_def |= h->dynamic_def; - if (hi->root.type == bfd_link_hash_indirect) + /* If we first saw a reference to @VER symbol with + non-default visibility, merge that visibility to the + @@VER symbol. */ + elf_merge_st_other (abfd, h, hi->other, sec, TRUE, dynamic); + + /* See if the new flags lead us to realize that the symbol + must be dynamic. */ + if (! *dynsym) { - (*bed->elf_backend_copy_indirect_symbol) (info, h, hi); - h->ref_dynamic_nonweak |= hi->ref_dynamic_nonweak; - hi->dynamic_def |= h->dynamic_def; - - /* If we first saw a reference to @VER symbol with - non-default visibility, merge that visibility to the - @@VER symbol. */ - elf_merge_st_other (abfd, h, hi->other, sec, TRUE, dynamic); - - /* See if the new flags lead us to realize that the symbol - must be dynamic. */ - if (! *dynsym) + if (! dynamic) { - if (! dynamic) - { - if (! bfd_link_executable (info) - || hi->ref_dynamic) - *dynsym = TRUE; - } - else - { - if (hi->ref_regular) - *dynsym = TRUE; - } + if (! bfd_link_executable (info) + || hi->ref_dynamic) + *dynsym = TRUE; + } + else + { + if (hi->ref_regular) + *dynsym = TRUE; } } } @@ -5060,8 +5077,10 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) /* Check to see if we need to add an indirect symbol for the default name. */ - if (definition - || (!override && h->root.type == bfd_link_hash_common)) + if ((definition + || (!override && h->root.type == bfd_link_hash_common)) + && !(hi != h + && hi->versioned == versioned_hidden)) if (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym, sec, value, &old_bfd, &dynsym)) goto error_free_vers; diff --git a/bfd/linker.c b/bfd/linker.c index 1357168456..6008a4452e 100644 --- a/bfd/linker.c +++ b/bfd/linker.c @@ -1301,7 +1301,7 @@ static const enum link_action link_action[8][8] = /* current\prev new undef undefw def defw com indr warn */ /* UNDEF_ROW */ {UND, NOACT, UND, REF, REF, NOACT, REFC, WARNC }, /* UNDEFW_ROW */ {WEAK, NOACT, NOACT, REF, REF, NOACT, REFC, WARNC }, - /* DEF_ROW */ {DEF, DEF, DEF, MDEF, DEF, CDEF, MDEF, CYCLE }, + /* DEF_ROW */ {DEF, DEF, DEF, MDEF, DEF, CDEF, MIND, CYCLE }, /* DEFW_ROW */ {DEFW, DEFW, DEFW, NOACT, NOACT, NOACT, NOACT, CYCLE }, /* COMMON_ROW */ {COM, COM, COM, CREF, COM, BIG, REFC, WARNC }, /* INDR_ROW */ {IND, IND, IND, MDEF, IND, CIND, MIND, CYCLE }, @@ -1672,6 +1672,17 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, case MIND: /* Multiple indirect symbols. This is OK if they both point to the same symbol. */ + if (h->u.i.link->type == bfd_link_hash_defweak) + { + /* It is also OK to redefine a symbol that indirects to + a weak definition. So for sym@ver -> sym@@ver where + sym@@ver is weak and we have a new strong sym@ver, + redefine sym@@ver. Of course if there exists + sym -> sym@@ver then this also redefines sym. */ + h = h->u.i.link; + cycle = TRUE; + break; + } if (strcmp (h->u.i.link->root.string, string) == 0) break; /* Fall through. */ diff --git a/ld/ChangeLog b/ld/ChangeLog index 4c5f0090d0..0bbb576c56 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,10 @@ +2020-12-04 Alan Modra + + * testsuite/ld-elf/pr26978a.d, + * testsuite/ld-elf/pr26978a.s, + * testsuite/ld-elf/pr26978b.d, + * testsuite/ld-elf/pr26978b.s: New tests. + 2020-12-03 Andreas Krebbel * testsuite/ld-s390/tlsbin_64.dd: The newly added jgnop mnemonic diff --git a/ld/testsuite/ld-elf/pr26978a.d b/ld/testsuite/ld-elf/pr26978a.d new file mode 100644 index 0000000000..969f34bee6 --- /dev/null +++ b/ld/testsuite/ld-elf/pr26978a.d @@ -0,0 +1,11 @@ +#source: pr26978a.s +#source: pr26978b.s +#target: [check_shared_lib_support] +#as: +#ld: -shared --version-script=pr26979.ver +#readelf: -sW + +#failif +#... +.*foo@v1 +#pass diff --git a/ld/testsuite/ld-elf/pr26978a.s b/ld/testsuite/ld-elf/pr26978a.s new file mode 100644 index 0000000000..abb035d1d0 --- /dev/null +++ b/ld/testsuite/ld-elf/pr26978a.s @@ -0,0 +1,4 @@ + .weak foo + .symver foo, foo@@@v1 +foo: + .octa 0 diff --git a/ld/testsuite/ld-elf/pr26978b.d b/ld/testsuite/ld-elf/pr26978b.d new file mode 100644 index 0000000000..fa290860cb --- /dev/null +++ b/ld/testsuite/ld-elf/pr26978b.d @@ -0,0 +1,11 @@ +#source: pr26978b.s +#source: pr26978a.s +#target: [check_shared_lib_support] +#as: +#ld: -shared --version-script=pr26979.ver +#readelf: -sW + +#failif +#... +.*foo@v1 +#pass diff --git a/ld/testsuite/ld-elf/pr26978b.s b/ld/testsuite/ld-elf/pr26978b.s new file mode 100644 index 0000000000..59b6ac2076 --- /dev/null +++ b/ld/testsuite/ld-elf/pr26978b.s @@ -0,0 +1,4 @@ + .globl foo_v1 + .symver foo_v1, foo@v1 +foo_v1: + .octa 0