[v2] elf: Verify that there is only one default version
Checks
| Context |
Check |
Description |
| linaro-tcwg-bot/tcwg_binutils_build--master-arm |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 |
success
|
Test passed
|
| linaro-tcwg-bot/tcwg_binutils_check--master-arm |
success
|
Test passed
|
Commit Message
On Wed, Aug 26, 2026 at 11:35 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> When assigning the symbol version, verify that there is only one default
> version.
>
Here is the v2 patch to provide info of where multiple default versions
are defined:
ld -shared -o pr34550.so pr34550a.o pr34550b.o --version-script pr34550.t
/usr/local/bin/ld: pr34550.so: multiple default versions of `fmod':
`GLIBC_2.0' in pr34550a.o and `GLIBC_2.43' in pr34550b.o.
/usr/local/bin/ld: failed to set dynamic section sizes: bad value
Comments
On Thu, Aug 27, 2026 at 08:12:55AM +0800, H.J. Lu wrote:
> When assigning the symbol version, verify that there is only one default
> version.
>
> bfd/
>
> PR ld/34550
> * elflink.c (_bfd_elf_link_assign_sym_version): Verify that there
> is only one default version.
>
> ld/
>
> PR ld/34550
> * testsuite/ld-elf/pr34550.d: New test.
> * testsuite/ld-elf/pr34550.t: Likewise.
> * testsuite/ld-elf/pr34550a.s: Likewise.
> * testsuite/ld-elf/pr34550b.s: Likewise.
OK if this has been tested properly over multiple targets.
From 43096b92b19323dbfbfe5ee41986c54032b96b92 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Wed, 26 Aug 2026 11:29:39 +0800
Subject: [PATCH v2] elf: Verify that there is only one default version
When assigning the symbol version, verify that there is only one default
version.
bfd/
PR ld/34550
* elflink.c (_bfd_elf_link_assign_sym_version): Verify that there
is only one default version.
ld/
PR ld/34550
* testsuite/ld-elf/pr34550.d: New test.
* testsuite/ld-elf/pr34550.t: Likewise.
* testsuite/ld-elf/pr34550a.s: Likewise.
* testsuite/ld-elf/pr34550b.s: Likewise.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
bfd/elflink.c | 52 +++++++++++++++++++++++++++++++++-
ld/testsuite/ld-elf/pr34550.d | 6 ++++
ld/testsuite/ld-elf/pr34550.t | 13 +++++++++
ld/testsuite/ld-elf/pr34550a.s | 5 ++++
ld/testsuite/ld-elf/pr34550b.s | 6 ++++
5 files changed, 81 insertions(+), 1 deletion(-)
create mode 100644 ld/testsuite/ld-elf/pr34550.d
create mode 100644 ld/testsuite/ld-elf/pr34550.t
create mode 100644 ld/testsuite/ld-elf/pr34550a.s
create mode 100644 ld/testsuite/ld-elf/pr34550b.s
@@ -2697,10 +2697,14 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
if (p != NULL && h->verinfo.vertree == NULL)
{
struct bfd_elf_version_tree *t;
+ bool default_version = false;
++p;
if (*p == ELF_VER_CHR)
- ++p;
+ {
+ default_version = true;
+ ++p;
+ }
/* If there is no version string, we can just return out. */
if (*p == '\0')
@@ -2714,6 +2718,52 @@ _bfd_elf_link_assign_sym_version (struct elf_link_hash_entry *h, void *data)
if (hide)
obed->elf_backend_hide_symbol (info, h, true);
+ else if (default_version)
+ {
+ /* Get the unversioned symbol for the default version. */
+ struct elf_link_hash_entry *h_u;
+ size_t size = p - h->root.root.string - 1;
+ char *unversioned_name = bfd_malloc (size);
+ if (unversioned_name == NULL)
+ {
+ sinfo->failed = true;
+ return false;
+ }
+ memcpy (unversioned_name, h->root.root.string, size - 1);
+ unversioned_name[size - 1] = 0;
+ h_u = elf_link_hash_lookup (elf_hash_table (info),
+ unversioned_name, false,
+ false, false);
+
+ /* There must be an unversioned symbol. */
+ if (h_u == NULL)
+ abort ();
+
+ while (h_u->root.type == bfd_link_hash_indirect
+ || h_u->root.type == bfd_link_hash_warning)
+ h_u = (struct elf_link_hash_entry *) h_u->root.u.i.link;
+
+ /* Verify that there is only one default version. */
+ if (h_u->versioned != versioned_hidden
+ && h_u->verinfo.vertree != h->verinfo.vertree)
+ {
+ /* xgettext:c-format */
+ info->callbacks->einfo
+ (_("%X%P: %pB: multiple default versions of `%s': "
+ "`%s' in %pB and `%s' in %pB.\n"),
+ info->output_bfd, unversioned_name,
+ h_u->verinfo.vertree->name,
+ h_u->root.u.def.section->owner,
+ h->verinfo.vertree->name,
+ h->root.u.def.section->owner);
+ bfd_set_error (bfd_error_bad_value);
+ sinfo->failed = true;
+ free (unversioned_name);
+ return false;
+ }
+
+ free (unversioned_name);
+ }
/* If we are building an application, we need to create a
version node for this version. */
new file mode 100644
@@ -0,0 +1,6 @@
+#source: pr34550a.s
+#source: pr34550b.s
+#target: [check_shared_lib_support]
+#as:
+#ld: -shared --version-script=pr34550.t
+#error: multiple default versions of `fmod': `GLIBC_2.0' in tmpdir/pr34550a.o and `GLIBC_2.43' in tmpdir/pr34550b.o.
new file mode 100644
@@ -0,0 +1,13 @@
+GLIBC_2.0 {
+ global:
+ fmod;
+ local:
+ *;
+};
+
+GLIBC_2.43 {
+ global:
+ fmod;
+ local:
+ *;
+} GLIBC_2.0;
new file mode 100644
@@ -0,0 +1,5 @@
+ .text
+ .type fmod,%function
+ .globl fmod
+fmod:
+ .dc.a 0
new file mode 100644
@@ -0,0 +1,6 @@
+ .text
+ .type fmod_new,%function
+ .globl fmod_new
+fmod_new:
+ .dc.a 0
+ .symver fmod_new, fmod@@GLIBC_2.43
--
2.55.0