diff options
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 12 | ||||
-rw-r--r-- | bfd/elflink.c | 83 | ||||
-rw-r--r-- | bfd/linker.c | 13 |
3 files changed, 75 insertions, 33 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index b3bcf9e..fa29df2 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,15 @@ +2020-12-04 Alan Modra <amodra@gmail.com> + + 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 <MIND>): Handle redefinition of + weak indirect symbol. + 2020-12-01 Nelson Chu <nelson.chu@sifive.com> * elfxx-riscv.c (riscv_parse_prefixed_ext): Use riscv_compare_subsets diff --git a/bfd/elflink.c b/bfd/elflink.c index 512c504..29b46f1 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 (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 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 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); + /* 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) + /* 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 1357168..6008a44 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. */ |