[v3] elf: Always append ".COUNT" to local symbols

Message ID CAMe9rOoAfE8q7EROBus-Y8rM3zhZv7-mZqk0EVm5m=tRYwSt6A@mail.gmail.com
State New
Headers show
Series
  • [v3] elf: Always append ".COUNT" to local symbols
Related show

Commit Message

H.J. Lu via Binutils May 6, 2021, 1:03 a.m.
On Wed, May 5, 2021 at 3:11 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>

> On Wed, May 5, 2021 at 2:36 PM Fangrui Song <i@maskray.me> wrote:

> >

> > On 2021-05-05, H.J. Lu via Binutils wrote:

> > >On Wed, May 5, 2021 at 11:31 AM H.J. Lu <hjl.tools@gmail.com> wrote:

> > >>

> > >> On Wed, May 5, 2021 at 8:48 AM H.J. Lu <hjl.tools@gmail.com> wrote:

> > >> >

> > >> > 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;

> > >

> > >> This scheme doesn't work.

> > >>

> > >

> > >This one works.

> > >

> > >--

> > >H.J.

> >

> > I don't read the implementation.

> >

> > If bar.2.1 already exists, can the implementation correctly rename bar.2 (to bar.2.2) ?

>

> Is this what you have in mind?

>

> [hjl@gnu-cfl-2 pr27825-2]$ cat pr27825a.s

> .text

> .globl _start

> _start:

> bar.2:

> .nop

> [hjl@gnu-cfl-2 pr27825-2]$ cat pr27825b.s

> .text

> bar.2:

> .nop

> [hjl@gnu-cfl-2 pr27825-2]$ cat pr27825c.s

> .text

> bar.1.1:

> bar.2.1:

> .nop

> [hjl@gnu-cfl-2 pr27825-2]$ make

> as   -o pr27825a.o pr27825a.s

> as   -o pr27825b.o pr27825b.s

> as   -o pr27825c.o pr27825c.s

> ./ld --emit-relocs -z unique-symbol -e _start -o x pr27825a.o

> pr27825b.o pr27825c.o

> ./nm x

> 0000000000401002 t bar.1.1

> 0000000000401000 t bar.2

> 0000000000401001 t bar.2.1

> 0000000000401002 t bar.2.1.1

> 0000000000402000 B __bss_start

> 0000000000402000 D _edata

> 0000000000402000 B _end

> 0000000000401000 T _start

> [hjl@gnu-cfl-2 pr27825-2]$

>


Here is the v3 patch to always append ".COUNT" to local symbols
to avoid potential conflicts with existing local symbol "XXX.COUNT".

-- 
H.J.

Comments

Fangrui Song May 6, 2021, 1:27 a.m. | #1
On 2021-05-05, H.J. Lu wrote:
>On Wed, May 5, 2021 at 3:11 PM H.J. Lu <hjl.tools@gmail.com> wrote:

>>

>> On Wed, May 5, 2021 at 2:36 PM Fangrui Song <i@maskray.me> wrote:

>> >

>> > On 2021-05-05, H.J. Lu via Binutils wrote:

>> > >On Wed, May 5, 2021 at 11:31 AM H.J. Lu <hjl.tools@gmail.com> wrote:

>> > >>

>> > >> On Wed, May 5, 2021 at 8:48 AM H.J. Lu <hjl.tools@gmail.com> wrote:

>> > >> >

>> > >> > 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;

>> > >

>> > >> This scheme doesn't work.

>> > >>

>> > >

>> > >This one works.

>> > >

>> > >--

>> > >H.J.

>> >

>> > I don't read the implementation.

>> >

>> > If bar.2.1 already exists, can the implementation correctly rename bar.2 (to bar.2.2) ?

>>

>> Is this what you have in mind?


Yes.

If foo cannot be used, try foo.1 foo.2 foo.3 ...
foo can itself be of the form bar.COUNT .

I guess the new code has handled the case.

(Personally I'd prefer zero-based numbering but one-based numbering
shouldn't hurt here.)

For the original FGKASLR (stalled?) request, the linker approach has a
drawback that the linker cannot change DW_AT_linkage_name in debug info,
so there may be a DW_AT_linkage_name / .symtab mismatch.

>> [hjl@gnu-cfl-2 pr27825-2]$ cat pr27825a.s

>> .text

>> .globl _start

>> _start:

>> bar.2:

>> .nop

>> [hjl@gnu-cfl-2 pr27825-2]$ cat pr27825b.s

>> .text

>> bar.2:

>> .nop

>> [hjl@gnu-cfl-2 pr27825-2]$ cat pr27825c.s

>> .text

>> bar.1.1:

>> bar.2.1:

>> .nop

>> [hjl@gnu-cfl-2 pr27825-2]$ make

>> as   -o pr27825a.o pr27825a.s

>> as   -o pr27825b.o pr27825b.s

>> as   -o pr27825c.o pr27825c.s

>> ./ld --emit-relocs -z unique-symbol -e _start -o x pr27825a.o

>> pr27825b.o pr27825c.o

>> ./nm x

>> 0000000000401002 t bar.1.1

>> 0000000000401000 t bar.2

>> 0000000000401001 t bar.2.1

>> 0000000000401002 t bar.2.1.1

>> 0000000000402000 B __bss_start

>> 0000000000402000 D _edata

>> 0000000000402000 B _end

>> 0000000000401000 T _start

>> [hjl@gnu-cfl-2 pr27825-2]$

>>

>

>Here is the v3 patch to always append ".COUNT" to local symbols

>to avoid potential conflicts with existing local symbol "XXX.COUNT".

>

>-- 

>H.J.
H.J. Lu via Binutils May 6, 2021, 2:15 a.m. | #2
On Wed, May 05, 2021 at 06:03:07PM -0700, H.J. Lu via Binutils wrote:
> Here is the v3 patch to always append ".COUNT" to local symbols

> to avoid potential conflicts with existing local symbol "XXX.COUNT".


Good.  OK, but only after you run the testsuite over many targets.

> 	* testsuite/ld-elf/pr27825-1.d: New file.

> 	* testsuite/ld-elf/pr27825-1a.s: Likewise.

> 	* testsuite/ld-elf/pr27825-1b.s: Likewise.

> 	* testsuite/ld-elf/pr27825-2.d: Likewise.

> 	* testsuite/ld-elf/pr27825-2a.s: Likewise.

> 	* testsuite/ld-elf/pr27825-2b.s: Likewise.


I'd rather not have to fix this up later.

-- 
Alan Modra
Australia Development Lab, IBM
H.J. Lu via Binutils May 6, 2021, 3:29 a.m. | #3
On Wed, May 5, 2021 at 7:15 PM Alan Modra <amodra@gmail.com> wrote:
>

> On Wed, May 05, 2021 at 06:03:07PM -0700, H.J. Lu via Binutils wrote:

> > Here is the v3 patch to always append ".COUNT" to local symbols

> > to avoid potential conflicts with existing local symbol "XXX.COUNT".

>

> Good.  OK, but only after you run the testsuite over many targets.

>

> >       * testsuite/ld-elf/pr27825-1.d: New file.

> >       * testsuite/ld-elf/pr27825-1a.s: Likewise.

> >       * testsuite/ld-elf/pr27825-1b.s: Likewise.

> >       * testsuite/ld-elf/pr27825-2.d: Likewise.

> >       * testsuite/ld-elf/pr27825-2a.s: Likewise.

> >       * testsuite/ld-elf/pr27825-2b.s: Likewise.

>

> I'd rather not have to fix this up later.

>


This is the patch I am checking in.

-- 
H.J.
From 57832de5b466fbe9fd64d9f52dfd5390c6a58ba2 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Wed, 5 May 2021 08:37:33 -0700
Subject: [PATCH] elf: Always append ".COUNT" to local symbols

Always append ".COUNT" to local symbols to avoid potential conflicts
with existing local symbol "XXX.COUNT".

bfd/

	PR ld/27825
	* elflink.c (elf_link_output_symstrtab): Always append ".COUNT"
	to local symbols.

ld/

	PR ld/27825
	* testsuite/ld-elf/pr27825-1.d: New file.
	* testsuite/ld-elf/pr27825-1a.s: Likewise.
	* testsuite/ld-elf/pr27825-1b.s: Likewise.
	* testsuite/ld-elf/pr27825-2.d: Likewise.
	* testsuite/ld-elf/pr27825-2a.s: Likewise.
	* testsuite/ld-elf/pr27825-2b.s: Likewise.
---
 bfd/elflink.c                    | 39 ++++++++++++++++----------------
 ld/testsuite/ld-elf/pr26391.nd   |  2 +-
 ld/testsuite/ld-elf/pr27825-1.d  | 21 +++++++++++++++++
 ld/testsuite/ld-elf/pr27825-1a.s |  7 ++++++
 ld/testsuite/ld-elf/pr27825-1b.s |  5 ++++
 ld/testsuite/ld-elf/pr27825-2.d  | 18 +++++++++++++++
 ld/testsuite/ld-elf/pr27825-2a.s |  5 ++++
 ld/testsuite/ld-elf/pr27825-2b.s |  3 +++
 ld/testsuite/ld-elf/pr27825-2c.s |  4 ++++
 9 files changed, 83 insertions(+), 21 deletions(-)
 create mode 100644 ld/testsuite/ld-elf/pr27825-1.d
 create mode 100644 ld/testsuite/ld-elf/pr27825-1a.s
 create mode 100644 ld/testsuite/ld-elf/pr27825-1b.s
 create mode 100644 ld/testsuite/ld-elf/pr27825-2.d
 create mode 100644 ld/testsuite/ld-elf/pr27825-2a.s
 create mode 100644 ld/testsuite/ld-elf/pr27825-2b.s
 create mode 100644 ld/testsuite/ld-elf/pr27825-2c.s

diff --git a/bfd/elflink.c b/bfd/elflink.c
index cb38a025349..0e1871aaac9 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -9830,6 +9830,9 @@ elf_link_output_symstrtab (void *finf,
 	       && ELF_ST_BIND (elfsym->st_info) == STB_LOCAL)
 	{
 	  struct local_hash_entry *lh;
+	  size_t count_len;
+	  size_t base_len;
+	  char buf[30];
 	  switch (ELF_ST_TYPE (elfsym->st_info))
 	    {
 	    case STT_FILE:
@@ -9840,28 +9843,24 @@ elf_link_output_symstrtab (void *finf,
 		     (&flinfo->local_hash_table, name, true, false);
 	      if (lh == NULL)
 		return 0;
-	      if (lh->count)
+	      /* Always append ".COUNT" to local symbols to avoid
+		 potential conflicts with local symbol "XXX.COUNT".  */
+	      sprintf (buf, "%lx", lh->count);
+	      base_len = lh->size;
+	      if (!base_len)
 		{
-		  /* Append ".COUNT" to duplicated local symbols.  */
-		  size_t count_len;
-		  size_t base_len = lh->size;
-		  char buf[30];
-		  sprintf (buf, "%lx", lh->count);
-		  if (!base_len)
-		    {
-		      base_len = strlen (name);
-		      lh->size = base_len;
-		    }
-		  count_len = strlen (buf);
-		  versioned_name = bfd_alloc (flinfo->output_bfd,
-					      base_len + count_len + 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);
+		  base_len = strlen (name);
+		  lh->size = base_len;
 		}
+	      count_len = strlen (buf);
+	      versioned_name = bfd_alloc (flinfo->output_bfd,
+					  base_len + count_len + 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);
 	      lh->count++;
 	      break;
 	    }
diff --git a/ld/testsuite/ld-elf/pr26391.nd b/ld/testsuite/ld-elf/pr26391.nd
index d01f3381340..07bfd7fb5b5 100644
--- a/ld/testsuite/ld-elf/pr26391.nd
+++ b/ld/testsuite/ld-elf/pr26391.nd
@@ -1,5 +1,5 @@
 #...
-[0-9a-z]+ [td] _?bar
+[0-9a-z]+ [td] _?bar.0
 #...
 [0-9a-z]+ [td] _?bar.1
 #...
diff --git a/ld/testsuite/ld-elf/pr27825-1.d b/ld/testsuite/ld-elf/pr27825-1.d
new file mode 100644
index 00000000000..c9b1b921f3d
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825-1.d
@@ -0,0 +1,21 @@
+#source: pr27825-1a.s
+#source: pr27825-1b.s
+#ld: -e _start --emit-relocs -z unique-symbol
+#nm: --defined-only
+#xfail: [is_generic]
+#xfail: fr30-*-* frv-*-* ft32-*-* iq2000-*-* mn10200-*-* msp*-* mt-*-*
+# These targets don't support -z.
+
+#...
+[0-9a-f]+ t bar.0
+#...
+[0-9a-f]+ t bar.1
+#...
+[0-9a-f]+ t bar.1.0
+#...
+[0-9a-f]+ t bar.1.1
+#...
+[0-9a-f]+ t bar.2.0
+#...
+[0-9a-f]+ t bar.2.1
+#pass
diff --git a/ld/testsuite/ld-elf/pr27825-1a.s b/ld/testsuite/ld-elf/pr27825-1a.s
new file mode 100644
index 00000000000..e6940e17430
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825-1a.s
@@ -0,0 +1,7 @@
+	.text
+	.globl _start
+_start:
+bar:
+bar.1:
+bar.2:
+	.nop
diff --git a/ld/testsuite/ld-elf/pr27825-1b.s b/ld/testsuite/ld-elf/pr27825-1b.s
new file mode 100644
index 00000000000..2128e802d4b
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825-1b.s
@@ -0,0 +1,5 @@
+	.text
+bar:
+bar.1:
+bar.2:
+	.nop
diff --git a/ld/testsuite/ld-elf/pr27825-2.d b/ld/testsuite/ld-elf/pr27825-2.d
new file mode 100644
index 00000000000..12a18636367
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825-2.d
@@ -0,0 +1,18 @@
+#source: pr27825-2a.s
+#source: pr27825-2b.s
+#source: pr27825-2c.s
+#ld: -e _start --emit-relocs -z unique-symbol
+#nm: --defined-only
+#xfail: [is_generic]
+#xfail: fr30-*-* frv-*-* ft32-*-* iq2000-*-* mn10200-*-* msp*-* mt-*-*
+# These targets don't support -z.
+
+#...
+[0-9a-f]+ t bar.0
+#...
+[0-9a-f]+ t bar.1
+#...
+[0-9a-f]+ t bar.1.0
+#...
+[0-9a-f]+ t bar.2.0
+#pass
diff --git a/ld/testsuite/ld-elf/pr27825-2a.s b/ld/testsuite/ld-elf/pr27825-2a.s
new file mode 100644
index 00000000000..40fc05bc537
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825-2a.s
@@ -0,0 +1,5 @@
+	.text
+	.globl _start
+_start:
+bar:
+	.nop
diff --git a/ld/testsuite/ld-elf/pr27825-2b.s b/ld/testsuite/ld-elf/pr27825-2b.s
new file mode 100644
index 00000000000..9e6f96a8bc7
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825-2b.s
@@ -0,0 +1,3 @@
+	.text
+bar:
+	.nop
diff --git a/ld/testsuite/ld-elf/pr27825-2c.s b/ld/testsuite/ld-elf/pr27825-2c.s
new file mode 100644
index 00000000000..762f8864e5d
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825-2c.s
@@ -0,0 +1,4 @@
+	.text
+bar.1:
+bar.2:
+	.nop

Patch

From 788ce54c036586ee155fcb4a6ed96078b0d0184a Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Wed, 5 May 2021 08:37:33 -0700
Subject: [PATCH v3] elf: Always append ".COUNT" to local symbols

Always append ".COUNT" to local symbols to avoid potential conflicts
with existing local symbol "XXX.COUNT".

bfd/

	PR ld/27825
	* elflink.c (elf_link_output_symstrtab): Always append ".COUNT"
	to local symbols.

ld/

	PR ld/27825
	* testsuite/ld-elf/pr27825-1.d: New file.
	* testsuite/ld-elf/pr27825-1a.s: Likewise.
	* testsuite/ld-elf/pr27825-1b.s: Likewise.
	* testsuite/ld-elf/pr27825-2.d: Likewise.
	* testsuite/ld-elf/pr27825-2a.s: Likewise.
	* testsuite/ld-elf/pr27825-2b.s: Likewise.
---
 bfd/elflink.c                    | 39 ++++++++++++++++----------------
 ld/testsuite/ld-elf/pr26391.nd   |  2 +-
 ld/testsuite/ld-elf/pr27825-1.d  | 18 +++++++++++++++
 ld/testsuite/ld-elf/pr27825-1a.s |  7 ++++++
 ld/testsuite/ld-elf/pr27825-1b.s |  5 ++++
 ld/testsuite/ld-elf/pr27825-2.d  | 15 ++++++++++++
 ld/testsuite/ld-elf/pr27825-2a.s |  5 ++++
 ld/testsuite/ld-elf/pr27825-2b.s |  3 +++
 ld/testsuite/ld-elf/pr27825-2c.s |  4 ++++
 9 files changed, 77 insertions(+), 21 deletions(-)
 create mode 100644 ld/testsuite/ld-elf/pr27825-1.d
 create mode 100644 ld/testsuite/ld-elf/pr27825-1a.s
 create mode 100644 ld/testsuite/ld-elf/pr27825-1b.s
 create mode 100644 ld/testsuite/ld-elf/pr27825-2.d
 create mode 100644 ld/testsuite/ld-elf/pr27825-2a.s
 create mode 100644 ld/testsuite/ld-elf/pr27825-2b.s
 create mode 100644 ld/testsuite/ld-elf/pr27825-2c.s

diff --git a/bfd/elflink.c b/bfd/elflink.c
index cb38a025349..0e1871aaac9 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -9830,6 +9830,9 @@  elf_link_output_symstrtab (void *finf,
 	       && ELF_ST_BIND (elfsym->st_info) == STB_LOCAL)
 	{
 	  struct local_hash_entry *lh;
+	  size_t count_len;
+	  size_t base_len;
+	  char buf[30];
 	  switch (ELF_ST_TYPE (elfsym->st_info))
 	    {
 	    case STT_FILE:
@@ -9840,28 +9843,24 @@  elf_link_output_symstrtab (void *finf,
 		     (&flinfo->local_hash_table, name, true, false);
 	      if (lh == NULL)
 		return 0;
-	      if (lh->count)
+	      /* Always append ".COUNT" to local symbols to avoid
+		 potential conflicts with local symbol "XXX.COUNT".  */
+	      sprintf (buf, "%lx", lh->count);
+	      base_len = lh->size;
+	      if (!base_len)
 		{
-		  /* Append ".COUNT" to duplicated local symbols.  */
-		  size_t count_len;
-		  size_t base_len = lh->size;
-		  char buf[30];
-		  sprintf (buf, "%lx", lh->count);
-		  if (!base_len)
-		    {
-		      base_len = strlen (name);
-		      lh->size = base_len;
-		    }
-		  count_len = strlen (buf);
-		  versioned_name = bfd_alloc (flinfo->output_bfd,
-					      base_len + count_len + 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);
+		  base_len = strlen (name);
+		  lh->size = base_len;
 		}
+	      count_len = strlen (buf);
+	      versioned_name = bfd_alloc (flinfo->output_bfd,
+					  base_len + count_len + 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);
 	      lh->count++;
 	      break;
 	    }
diff --git a/ld/testsuite/ld-elf/pr26391.nd b/ld/testsuite/ld-elf/pr26391.nd
index d01f3381340..07bfd7fb5b5 100644
--- a/ld/testsuite/ld-elf/pr26391.nd
+++ b/ld/testsuite/ld-elf/pr26391.nd
@@ -1,5 +1,5 @@ 
 #...
-[0-9a-z]+ [td] _?bar
+[0-9a-z]+ [td] _?bar.0
 #...
 [0-9a-z]+ [td] _?bar.1
 #...
diff --git a/ld/testsuite/ld-elf/pr27825-1.d b/ld/testsuite/ld-elf/pr27825-1.d
new file mode 100644
index 00000000000..915e2acce0f
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825-1.d
@@ -0,0 +1,18 @@ 
+#source: pr27825-1a.s
+#source: pr27825-1b.s
+#ld: -e _start --emit-relocs -z unique-symbol
+#nm: --defined-only
+
+#...
+[0-9a-f]+ t bar.0
+#...
+[0-9a-f]+ t bar.1
+#...
+[0-9a-f]+ t bar.1.0
+#...
+[0-9a-f]+ t bar.1.1
+#...
+[0-9a-f]+ t bar.2.0
+#...
+[0-9a-f]+ t bar.2.1
+#pass
diff --git a/ld/testsuite/ld-elf/pr27825-1a.s b/ld/testsuite/ld-elf/pr27825-1a.s
new file mode 100644
index 00000000000..e6940e17430
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825-1a.s
@@ -0,0 +1,7 @@ 
+	.text
+	.globl _start
+_start:
+bar:
+bar.1:
+bar.2:
+	.nop
diff --git a/ld/testsuite/ld-elf/pr27825-1b.s b/ld/testsuite/ld-elf/pr27825-1b.s
new file mode 100644
index 00000000000..2128e802d4b
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825-1b.s
@@ -0,0 +1,5 @@ 
+	.text
+bar:
+bar.1:
+bar.2:
+	.nop
diff --git a/ld/testsuite/ld-elf/pr27825-2.d b/ld/testsuite/ld-elf/pr27825-2.d
new file mode 100644
index 00000000000..74099ba4693
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825-2.d
@@ -0,0 +1,15 @@ 
+#source: pr27825-2a.s
+#source: pr27825-2b.s
+#source: pr27825-2c.s
+#ld: -e _start --emit-relocs -z unique-symbol
+#nm: --defined-only
+
+#...
+[0-9a-f]+ t bar.0
+#...
+[0-9a-f]+ t bar.1
+#...
+[0-9a-f]+ t bar.1.0
+#...
+[0-9a-f]+ t bar.2.0
+#pass
diff --git a/ld/testsuite/ld-elf/pr27825-2a.s b/ld/testsuite/ld-elf/pr27825-2a.s
new file mode 100644
index 00000000000..40fc05bc537
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825-2a.s
@@ -0,0 +1,5 @@ 
+	.text
+	.globl _start
+_start:
+bar:
+	.nop
diff --git a/ld/testsuite/ld-elf/pr27825-2b.s b/ld/testsuite/ld-elf/pr27825-2b.s
new file mode 100644
index 00000000000..9e6f96a8bc7
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825-2b.s
@@ -0,0 +1,3 @@ 
+	.text
+bar:
+	.nop
diff --git a/ld/testsuite/ld-elf/pr27825-2c.s b/ld/testsuite/ld-elf/pr27825-2c.s
new file mode 100644
index 00000000000..762f8864e5d
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr27825-2c.s
@@ -0,0 +1,4 @@ 
+	.text
+bar.1:
+bar.2:
+	.nop
-- 
2.31.1