[PATCH] elf: Avoid conflicts with local symbol names of "XXX.COUNT"

H.J. Lu hjl.tools@gmail.com
Wed May 5 15:48:55 GMT 2021


When appending ".COUNT" to duplicated local symbol names of "XXX",
increment COUNT if there is an existing local symbol name of "XXX.COUNT".

bfd/

	PR ld/27825
	* elflink.c (elf_link_output_symstrtab): Avoid conflicts with
	local symbol names of "XXX.COUNT".

ld/

	PR ld/27825
	* testsuite/ld-elf/pr27825.d: New file.
	* testsuite/ld-elf/pr27825a.s: Likewise.
	* testsuite/ld-elf/pr27825b.s: Likewise.
---
 bfd/elflink.c                  | 31 ++++++++++++++++++++++++++++---
 ld/testsuite/ld-elf/pr27825.d  | 18 ++++++++++++++++++
 ld/testsuite/ld-elf/pr27825a.s |  7 +++++++
 ld/testsuite/ld-elf/pr27825b.s |  5 +++++
 4 files changed, 58 insertions(+), 3 deletions(-)
 create mode 100644 ld/testsuite/ld-elf/pr27825.d
 create mode 100644 ld/testsuite/ld-elf/pr27825a.s
 create mode 100644 ld/testsuite/ld-elf/pr27825b.s

diff --git a/bfd/elflink.c b/bfd/elflink.c
index cb38a025349..ac46585f0ab 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -9845,22 +9845,47 @@ elf_link_output_symstrtab (void *finf,
 		  /* Append ".COUNT" to duplicated local symbols.  */
 		  size_t count_len;
 		  size_t base_len = lh->size;
-		  char buf[30];
-		  sprintf (buf, "%lx", lh->count);
+		  char buf[20];
+		  if (snprintf (buf, sizeof (buf), "%lx", lh->count)
+		      >= (int) sizeof (buf))
+		    return 0;
 		  if (!base_len)
 		    {
 		      base_len = strlen (name);
 		      lh->size = base_len;
 		    }
 		  count_len = strlen (buf);
+		  /* NB: Allocate the extra suffix buffer for possible
+		     change.  */
 		  versioned_name = bfd_alloc (flinfo->output_bfd,
-					      base_len + count_len + 2);
+					      base_len + sizeof (buf)
+					      + 2);
 		  if (versioned_name == NULL)
 		    return 0;
 		  memcpy (versioned_name, name, base_len);
 		  versioned_name[base_len] = '.';
 		  memcpy (versioned_name + base_len + 1, buf,
 			  count_len + 1);
+		  do
+		    {
+		      /* Avoid conflicts with local symbol names of
+			 "XXX.COUNT".  */
+		      struct local_hash_entry *lvh
+			= (struct local_hash_entry *) bfd_hash_lookup
+			(&flinfo->local_hash_table, versioned_name,
+			 false, false);
+		      if (lvh == NULL)
+			break;
+		      lh->count++;
+		      if (snprintf (buf, sizeof (buf), "%lx",
+				    lh->count) >= (int) sizeof (buf))
+			return 0;
+		      count_len = strlen (buf);
+		      /* NB: Use the existing suffix buffer.  */
+		      memcpy (versioned_name + base_len + 1, buf,
+			      count_len + 1);
+		    }
+		  while (1);
 		}
 	      lh->count++;
 	      break;
diff --git a/ld/testsuite/ld-elf/pr27825.d b/ld/testsuite/ld-elf/pr27825.d
new file mode 100644
index 00000000000..da9832be850
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825.d
@@ -0,0 +1,18 @@
+#source: pr27825a.s
+#source: pr27825b.s
+#ld: -e _start --emit-relocs -z unique-symbol
+#nm: --defined-only
+
+#...
+[0-9a-f]+ t bar
+#...
+[0-9a-f]+ t bar.1
+#...
+[0-9a-f]+ t bar.1.1
+#...
+[0-9a-f]+ t bar.2
+#...
+[0-9a-f]+ t bar.2.1
+#...
+[0-9a-f]+ t bar.3
+#pass
diff --git a/ld/testsuite/ld-elf/pr27825a.s b/ld/testsuite/ld-elf/pr27825a.s
new file mode 100644
index 00000000000..e6940e17430
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825a.s
@@ -0,0 +1,7 @@
+	.text
+	.globl _start
+_start:
+bar:
+bar.1:
+bar.2:
+	.nop
diff --git a/ld/testsuite/ld-elf/pr27825b.s b/ld/testsuite/ld-elf/pr27825b.s
new file mode 100644
index 00000000000..2128e802d4b
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825b.s
@@ -0,0 +1,5 @@
+	.text
+bar:
+bar.1:
+bar.2:
+	.nop
-- 
2.31.1



More information about the Binutils mailing list