aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog12
-rw-r--r--bfd/elflink.c83
-rw-r--r--bfd/linker.c13
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. */