elf: Add -z unique-symbol to avoid duplicated local symbol names
authorH.J. Lu <hjl.tools@gmail.com>
Sat, 12 Sep 2020 12:37:30 +0000 (05:37 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Sat, 12 Sep 2020 12:37:43 +0000 (05:37 -0700)
The symbol string table in the .symtab section is optional and cosmetic.
The contents of the .symtab section have no impact on run-time execution.
The symbol names in the symbol string table help distinguish addresses at
different locations.  Add a linker option, -z unique-symbol, to avoid
duplicated local symbol names in the symbol string table.

This feature was well received by the livepatch maintainers.  It not only
solves the duplicated local symbol name problem, but also would allow
livepatch to more precisely locate duplicate symbols in general for
patching.

bfd/

PR ld/26391
* elflink.c (elf_final_link_info): Add local_hash_table.
(local_hash_entry): New.
(local_hash_newfunc): Likewise.
(elf_link_output_symstrtab): Append ".COUNT" to duplicated local
symbols.
(bfd_elf_final_link): Initialize and free local_hash_table for
"-z unique-symbol".

include/

PR ld/26391
* bfdlink.h (bfd_link_info): Add unique_symbol.

ld/

PR ld/26391
* NEWS: Mention "-z unique-symbol".
* emultempl/elf.em (gld${EMULATION_NAME}_handle_option): Handle
"-z unique-symbol" and "-z nounique-symbol".
* ld.texi: Document "-z unique-symbol" and "-z nounique-symbol".
* lexsup.c (elf_static_list_options): Add "-z unique-symbol" and
"-z nounique-symbol".
* testsuite/ld-elf/elf.exp: Add PR ld/26391 tests.
* testsuite/ld-elf/pr26391.nd: New file.
* testsuite/ld-elf/pr26391.out: Likewise.
* testsuite/ld-elf/pr26391a.c: Likewise.
* testsuite/ld-elf/pr26391b.c: Likewise.
* testsuite/ld-elf/pr26391c.c: Likewise.
* testsuite/ld-elf/pr26391d.c: Likewise.

16 files changed:
bfd/ChangeLog
bfd/elflink.c
include/ChangeLog
include/bfdlink.h
ld/ChangeLog
ld/NEWS
ld/emultempl/elf.em
ld/ld.texi
ld/lexsup.c
ld/testsuite/ld-elf/elf.exp
ld/testsuite/ld-elf/pr26391.nd [new file with mode: 0644]
ld/testsuite/ld-elf/pr26391.out [new file with mode: 0644]
ld/testsuite/ld-elf/pr26391a.c [new file with mode: 0644]
ld/testsuite/ld-elf/pr26391b.c [new file with mode: 0644]
ld/testsuite/ld-elf/pr26391c.c [new file with mode: 0644]
ld/testsuite/ld-elf/pr26391d.c [new file with mode: 0644]

index 19415d6b9f13cce86f7e89db1a16ea00f9f35180..4f0faa5c3ae98e76d72f84bf56f6a348ec77a635 100644 (file)
@@ -1,3 +1,14 @@
+2020-09-12  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR ld/26391
+       * elflink.c (elf_final_link_info): Add local_hash_table.
+       (local_hash_entry): New.
+       (local_hash_newfunc): Likewise.
+       (elf_link_output_symstrtab): Append ".COUNT" to duplicated local
+       symbols.
+       (bfd_elf_final_link): Initialize and free local_hash_table for
+       "-z unique-symbol".
+
 2020-09-10  Siddhesh Poyarekar  <siddesh.poyarekar@arm.com>
 
        * elfnn-aarch64.c (elfNN_aarch64_final_link_relocate): Revert
index 0e339f3c1ea44f745767115d1373937e5479af29..b6937293e8fb0894977f7901213955edc58d426b 100644 (file)
@@ -8401,8 +8401,49 @@ struct elf_final_link_info
   Elf_External_Sym_Shndx *symshndxbuf;
   /* Number of STT_FILE syms seen.  */
   size_t filesym_count;
+  /* Local symbol hash table.  */
+  struct bfd_hash_table local_hash_table;
 };
 
+struct local_hash_entry
+{
+  /* Base hash table entry structure.  */
+  struct bfd_hash_entry root;
+  /* Size of the local symbol name.  */
+  size_t size;
+  /* Number of the duplicated local symbol names.  */
+  long count;
+};
+
+/* Create an entry in the local symbol hash table.  */
+
+static struct bfd_hash_entry *
+local_hash_newfunc (struct bfd_hash_entry *entry,
+                   struct bfd_hash_table *table,
+                   const char *string)
+{
+
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (entry == NULL)
+    {
+      entry = bfd_hash_allocate (table,
+                                sizeof (struct local_hash_entry));
+      if (entry == NULL)
+        return entry;
+    }
+
+  /* Call the allocation method of the superclass.  */
+  entry = bfd_hash_newfunc (entry, table, string);
+  if (entry != NULL)
+    {
+      ((struct local_hash_entry *) entry)->count = 0;
+      ((struct local_hash_entry *) entry)->size = 0;
+    }
+
+  return entry;
+}
+
 /* This struct is used to pass information to elf_link_output_extsym.  */
 
 struct elf_outext_info
@@ -9666,23 +9707,66 @@ elf_link_output_symstrtab (struct elf_final_link_info *flinfo,
       /* Call _bfd_elf_strtab_offset after _bfd_elf_strtab_finalize
         to get the final offset for st_name.  */
       char *versioned_name = (char *) name;
-      if (h != NULL && h->versioned == versioned && h->def_dynamic)
-       {
-         /* Keep only one '@' for versioned symbols defined in shared
-            objects.  */
-         char *version = strrchr (name, ELF_VER_CHR);
-         char *base_end = strchr (name, ELF_VER_CHR);
-         if (version != base_end)
-           {
-             size_t base_len;
-             size_t len = strlen (name);
-             versioned_name = bfd_alloc (flinfo->output_bfd, len);
-             if (versioned_name == NULL)
+      if (h != NULL)
+       {
+         if (h->versioned == versioned && h->def_dynamic)
+           {
+             /* Keep only one '@' for versioned symbols defined in
+                shared objects.  */
+             char *version = strrchr (name, ELF_VER_CHR);
+             char *base_end = strchr (name, ELF_VER_CHR);
+             if (version != base_end)
+               {
+                 size_t base_len;
+                 size_t len = strlen (name);
+                 versioned_name = bfd_alloc (flinfo->output_bfd, len);
+                 if (versioned_name == NULL)
+                   return 0;
+                 base_len = base_end - name;
+                 memcpy (versioned_name, name, base_len);
+                 memcpy (versioned_name + base_len, version,
+                         len - base_len);
+               }
+           }
+       }
+      else if (flinfo->info->unique_symbol
+              && ELF_ST_BIND (elfsym->st_info) == STB_LOCAL)
+       {
+         struct local_hash_entry *lh;
+         switch (ELF_ST_TYPE (elfsym->st_info))
+           {
+           case STT_FILE:
+           case STT_SECTION:
+             break;
+           default:
+             lh = (struct local_hash_entry *) bfd_hash_lookup
+                    (&flinfo->local_hash_table, name, TRUE, FALSE);
+             if (lh == NULL)
                return 0;
-             base_len = base_end - name;
-             memcpy (versioned_name, name, base_len);
-             memcpy (versioned_name + base_len, version,
-                     len - base_len);
+             if (lh->count)
+               {
+                 /* 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);
+               }
+             lh->count++;
+             break;
            }
        }
       elfsym->st_name
@@ -11996,6 +12080,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   const char *std_attrs_section;
   struct elf_link_hash_table *htab = elf_hash_table (info);
   bfd_boolean sections_removed;
+  bfd_boolean ret;
 
   if (!is_elf_hash_table (htab))
     return FALSE;
@@ -12009,6 +12094,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   emit_relocs = (bfd_link_relocatable (info)
                 || info->emitrelocations);
 
+  memset (&flinfo, 0, sizeof (flinfo));
   flinfo.info = info;
   flinfo.output_bfd = abfd;
   flinfo.symstrtab = _bfd_elf_strtab_init ();
@@ -12028,16 +12114,11 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       /* Note that it is OK if symver_sec is NULL.  */
     }
 
-  flinfo.contents = NULL;
-  flinfo.external_relocs = NULL;
-  flinfo.internal_relocs = NULL;
-  flinfo.external_syms = NULL;
-  flinfo.locsym_shndx = NULL;
-  flinfo.internal_syms = NULL;
-  flinfo.indices = NULL;
-  flinfo.sections = NULL;
-  flinfo.symshndxbuf = NULL;
-  flinfo.filesym_count = 0;
+  if (info->unique_symbol
+      && !bfd_hash_table_init (&flinfo.local_hash_table,
+                              local_hash_newfunc,
+                              sizeof (struct local_hash_entry)))
+    return FALSE;
 
   /* The object attributes have been merged.  Remove the input
      sections from the link, and set the contents of the output
@@ -12572,6 +12653,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
          }
     }
 
+  ret = TRUE;
+
   /* Output any global symbols that got converted to local in a
      version script or due to symbol visibility.  We do this in a
      separate step since ELF requires all local symbols to appear
@@ -12584,7 +12667,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   eoinfo.file_sym_done = FALSE;
   bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
   if (eoinfo.failed)
-    return FALSE;
+    {
+      ret = FALSE;
+      goto return_local_hash_table;
+    }
 
   /* If backend needs to output some local symbols not present in the hash
      table, do it now.  */
@@ -12598,7 +12684,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       if (! ((*bed->elf_backend_output_arch_local_syms)
             (abfd, info, &flinfo,
              (out_sym_func) elf_link_output_symstrtab)))
-       return FALSE;
+       {
+         ret = FALSE;
+         goto return_local_hash_table;
+       }
     }
 
   /* That wrote out all the local symbols.  Finish up the symbol table
@@ -12645,7 +12734,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
              BFD_ASSERT (indx > 0);
              sym.st_shndx = indx;
              if (! check_dynsym (abfd, &sym))
-               return FALSE;
+               {
+                 ret = FALSE;
+                 goto return_local_hash_table;
+               }
              sym.st_value = s->vma;
              dest = dynsym + dynindx * bed->s->sizeof_sym;
              bed->s->swap_symbol_out (abfd, &sym, dest, 0);
@@ -12677,7 +12769,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
                  sym.st_shndx =
                    elf_section_data (s->output_section)->this_idx;
                  if (! check_dynsym (abfd, &sym))
-                   return FALSE;
+                   {
+                     ret = FALSE;
+                     goto return_local_hash_table;
+                   }
                  sym.st_value = (s->output_section->vma
                                  + s->output_offset
                                  + e->isym.st_value);
@@ -12695,7 +12790,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   eoinfo.flinfo = &flinfo;
   bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
   if (eoinfo.failed)
-    return FALSE;
+    {
+      ret = FALSE;
+      goto return_local_hash_table;
+    }
 
   /* If backend needs to output some symbols not present in the hash
      table, do it now.  */
@@ -12709,7 +12807,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       if (! ((*bed->elf_backend_output_arch_syms)
             (abfd, info, &flinfo,
              (out_sym_func) elf_link_output_symstrtab)))
-       return FALSE;
+       {
+         ret = FALSE;
+         goto return_local_hash_table;
+       }
     }
 
   /* Finalize the .strtab section.  */
@@ -12717,7 +12818,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
   /* Swap out the .strtab section. */
   if (!elf_link_swap_symbols_out (&flinfo))
-    return FALSE;
+    {
+      ret = FALSE;
+      goto return_local_hash_table;
+    }
 
   /* Now we know the size of the symtab section.  */
   if (bfd_get_symcount (abfd) > 0)
@@ -12744,7 +12848,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
              if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0
                  || (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt))
-               return FALSE;
+               {
+                 ret = FALSE;
+                 goto return_local_hash_table;
+               }
            }
        }
 
@@ -12766,14 +12873,18 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 
       if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0
          || ! _bfd_elf_strtab_emit (abfd, flinfo.symstrtab))
-       return FALSE;
+       {
+         ret = FALSE;
+         goto return_local_hash_table;
+       }
     }
 
   if (info->out_implib_bfd && !elf_output_implib (abfd, info))
     {
       _bfd_error_handler (_("%pB: failed to generate import library"),
                          info->out_implib_bfd);
-      return FALSE;
+      ret = FALSE;
+      goto return_local_hash_table;
     }
 
   /* Adjust the relocs to have the correct symbol indices.  */
@@ -12788,10 +12899,16 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
       sort = bed->sort_relocs_p == NULL || (*bed->sort_relocs_p) (o);
       if (esdo->rel.hdr != NULL
          && !elf_link_adjust_relocs (abfd, o, &esdo->rel, sort, info))
-       return FALSE;
+       {
+         ret = FALSE;
+         goto return_local_hash_table;
+       }
       if (esdo->rela.hdr != NULL
          && !elf_link_adjust_relocs (abfd, o, &esdo->rela, sort, info))
-       return FALSE;
+       {
+         ret = FALSE;
+         goto return_local_hash_table;
+       }
 
       /* Set the reloc_count field to 0 to prevent write_relocs from
         trying to swap the relocs out itself.  */
@@ -13110,17 +13227,25 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
     {
       bfd_byte *contents = (bfd_byte *) bfd_malloc (attr_size);
       if (contents == NULL)
-       return FALSE;   /* Bail out and fail.  */
+       {
+         /* Bail out and fail.  */
+         ret = FALSE;
+         goto return_local_hash_table;
+       }
       bfd_elf_set_obj_attr_contents (abfd, contents, attr_size);
       bfd_set_section_contents (abfd, attr_section, contents, 0, attr_size);
       free (contents);
     }
 
-  return TRUE;
+ return_local_hash_table:
+  if (info->unique_symbol)
+    bfd_hash_table_free (&flinfo.local_hash_table);
+  return ret;
 
  error_return:
   elf_final_link_free (abfd, &flinfo);
-  return FALSE;
+  ret = FALSE;
+  goto return_local_hash_table;
 }
 \f
 /* Initialize COOKIE for input bfd ABFD.  */
index c8a90cfa36bac8d68c583ea294ad604db61590aa..38baf59ca4d750b254a931433840175c954e238e 100644 (file)
@@ -1,3 +1,8 @@
+2020-09-12  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR ld/26391
+       * bfdlink.h (bfd_link_info): Add unique_symbol.
+
 2020-09-11  Felix Willgerodt  <felix.willgerodt@intel.com>
 
        Sync with GCC
index 3badfbdb19f017358065f4dee2dfc60e65c2f2c2..55020e31f454261df862a11a7481f31b1cc910aa 100644 (file)
@@ -523,6 +523,9 @@ struct bfd_link_info
      the linker.  */
   unsigned int non_contiguous_regions_warnings : 1;
 
+  /* TRUE if all symbol names should be unique.  */
+  unsigned int unique_symbol : 1;
+
   /* Char that may appear as the first char of a symbol, but should be
      skipped (like symbol_leading_char) when looking up symbols in
      wrap_hash.  Used by PowerPC Linux for 'dot' symbols.  */
index d81ebcc6c0101c83dba60704a438818a6b1ac43b..8d63f66c66e62934e044496b8543f0a1a024f464 100644 (file)
@@ -1,3 +1,20 @@
+2020-09-12  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR ld/26391
+       * NEWS: Mention "-z unique-symbol".
+       * emultempl/elf.em (gld${EMULATION_NAME}_handle_option): Handle
+       "-z unique-symbol" and "-z nounique-symbol".
+       * ld.texi: Document "-z unique-symbol" and "-z nounique-symbol".
+       * lexsup.c (elf_static_list_options): Add "-z unique-symbol" and
+       "-z nounique-symbol".
+       * testsuite/ld-elf/elf.exp: Add PR ld/26391 tests.
+       * testsuite/ld-elf/pr26391.nd: New file.
+       * testsuite/ld-elf/pr26391.out: Likewise.
+       * testsuite/ld-elf/pr26391a.c: Likewise.
+       * testsuite/ld-elf/pr26391b.c: Likewise.
+       * testsuite/ld-elf/pr26391c.c: Likewise.
+       * testsuite/ld-elf/pr26391d.c: Likewise.
+
 2020-09-11  Jeremy Drake  <sourceware-bugzilla@jdrake.com>
 
        PR 26588
diff --git a/ld/NEWS b/ld/NEWS
index 695348141b88e3c34f0ec89da464a83a10fa92a6..e4ae43b257d2297462c527a2b2328d70fa8ce8c5 100644 (file)
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,7 @@
 -*- text -*-
 
+* Add -z unique-symbol to avoid duplicated local symbol names.
+
 * The creation of PE format DLLs now defaults to using a more secure set of DLL
   characteristics.
 
index 356f34538b0d20ba344441feed23f6b00787a48e..59eed707ea7d6347d6df713b4ec4972e3f831168 100644 (file)
@@ -751,6 +751,10 @@ fragment <<EOF
          link_info.noexecstack = TRUE;
          link_info.execstack = FALSE;
        }
+      else if (strcmp (optarg, "unique-symbol") == 0)
+       link_info.unique_symbol = TRUE;
+      else if (strcmp (optarg, "nounique-symbol") == 0)
+       link_info.unique_symbol = FALSE;
       else if (strcmp (optarg, "globalaudit") == 0)
        {
          link_info.flags_1 |= DF_1_GLOBAUDIT;
index 7d961c3bb8e747f32590eaa86b905b3643f3556b..ee592df6c244da5a331d0a8d9307e37e01bebca3 100644 (file)
@@ -1378,6 +1378,12 @@ specifies a memory segment that should contain only instructions and must
 be in wholly disjoint pages from any other data.  Don't create separate
 code @code{PT_LOAD} segment if @samp{noseparate-code} is used.
 
+@item unique-symbol
+@itemx nounique-symbol
+Avoid duplicated local symbol names in the symbol string table.  Append
+".@code{number}" to duplicated local symbol names if @samp{unique-symbol}
+is used.  @option{nounique-symbol} is the default.
+
 @item shstk
 Generate GNU_PROPERTY_X86_FEATURE_1_SHSTK in .note.gnu.property section
 to indicate compatibility with Intel Shadow Stack.  Supported for
index b9cc8a1e957ee70a64101a65c19095a843b0f39a..b8f066745f374cb03a3d74c32eef340df0da9a0b 100644 (file)
@@ -2050,6 +2050,10 @@ elf_static_list_options (FILE *file)
   fprintf (file, _("\
   -z noexecstack              Mark executable as not requiring executable stack\n"));
   fprintf (file, _("\
+  -z unique-symbol            Avoid duplicated local symbol names\n"));
+  fprintf (file, _("\
+  -z nounique-symbol          Keep duplicated local symbol names (default)\n"));
+  fprintf (file, _("\
   -z globalaudit              Mark executable requiring global auditing\n"));
 }
 
index c0d67d80d27af284353a3c6d0b6f5eca5f0d04e8..f2ff0397c76148aea83012bf9198e74ecdae937b 100644 (file)
@@ -359,4 +359,125 @@ if { [istarget *-*-linux*]
 
 run_ld_link_exec_tests $array_tests_static $xfails
 
+run_cc_link_tests [list \
+    [list \
+       "Build pr26391-1" \
+       "-Wl,-z,unique-symbol" \
+       "-fno-function-sections" \
+       {pr26391a.c pr26391b.c pr26391c.c pr26391d.c} \
+       {{nm "" pr26391.nd}} \
+       "pr26391-1" \
+    ] \
+    [list \
+       "Build pr26391-2" \
+       "-Wl,-z,unique-symbol" \
+       "-ffunction-sections" \
+       {pr26391a.c pr26391b.c pr26391c.c pr26391d.c} \
+       {{nm "" pr26391.nd}} \
+       "pr26391-2" \
+    ] \
+    [list \
+       "Build pr26391-3" \
+       "-Wl,-z,unique-symbol,--emit-relocs" \
+       "-fno-function-sections" \
+       {pr26391a.c pr26391b.c pr26391c.c pr26391d.c} \
+       {{nm "" pr26391.nd}} \
+       "pr26391-3" \
+    ] \
+    [list \
+       "Build pr26391-4" \
+       "-Wl,-z,unique-symbol,--emit-relocs" \
+       "-ffunction-sections" \
+       {pr26391a.c pr26391b.c pr26391c.c pr26391d.c} \
+       {{nm "" pr26391.nd}} \
+       "pr26391-4" \
+    ] \
+]
+
+run_ld_link_tests [list \
+    [list \
+       "Build pr26391-5.o" \
+       "-z unique-symbol -r" \
+       "" \
+       "" \
+       {pr26391a.c pr26391b.c pr26391c.c pr26391d.c} \
+       {{nm "" pr26391.nd}} \
+       "pr26391-5.o" \
+       "-fno-function-sections" \
+    ] \
+    [list \
+       "Build pr26391-6.o" \
+       "-z unique-symbol -r" \
+       "" \
+       "" \
+       {pr26391a.c pr26391b.c pr26391c.c pr26391d.c} \
+       {{nm "" pr26391.nd}} \
+       "pr26391-6.o" \
+       "-ffunction-sections" \
+    ] \
+]
+
+run_ld_link_exec_tests [list \
+    [list \
+       "Run pr26391-1" \
+       "-Wl,-z,unique-symbol" \
+       "" \
+       {pr26391a.c pr26391b.c pr26391c.c pr26391d.c} \
+       "pr26391-1" \
+       "pr26391.out" \
+       "-fno-function-sections" \
+    ] \
+    [list \
+       "Run pr26391-2" \
+       "-Wl,-z,unique-symbol" \
+       "" \
+       {pr26391a.c pr26391b.c pr26391c.c pr26391d.c} \
+       "pr26391-2" \
+       "pr26391.out" \
+       "-ffunction-sections" \
+    ] \
+    [list \
+       "Run pr26391-3" \
+       "-Wl,-z,unique-symbol,--emit-relocs" \
+       "" \
+       {pr26391a.c pr26391b.c pr26391c.c pr26391d.c} \
+       "pr26391-3" \
+       "pr26391.out" \
+       "-fno-function-sections" \
+    ] \
+    [list \
+       "Run pr26391-4" \
+       "-Wl,-z,unique-symbol,--emit-relocs" \
+       "" \
+       {pr26391a.c pr26391b.c pr26391c.c pr26391d.c} \
+       "pr26391-4" \
+       "pr26391.out" \
+       "-ffunction-sections" \
+    ] \
+    [list \
+       "Run pr26391-5" \
+       "-Wl,-z,unique-symbol" \
+       "" \
+       {dummy.c} \
+       "pr26391-5" \
+       "pr26391.out" \
+       "" \
+       "c" \
+       "" \
+       "tmpdir/pr26391-5.o" \
+    ] \
+    [list \
+       "Run pr26391-6" \
+       "-Wl,-z,unique-symbol" \
+       "" \
+       {dummy.c} \
+       "pr26391-6" \
+       "pr26391.out" \
+       "" \
+       "c" \
+       "" \
+       "tmpdir/pr26391-6.o" \
+    ] \
+]
+
 catch "exec rm -f tmpdir/preinit tmpdir/init tmpdir/fini tmpdir/init-mixed" status
diff --git a/ld/testsuite/ld-elf/pr26391.nd b/ld/testsuite/ld-elf/pr26391.nd
new file mode 100644 (file)
index 0000000..8dd48d9
--- /dev/null
@@ -0,0 +1,7 @@
+#...
+[0-9a-z]+ t _?bar
+#...
+[0-9a-z]+ t _?bar.1
+#...
+[0-9a-z]+ t _?bar.2
+#pass
diff --git a/ld/testsuite/ld-elf/pr26391.out b/ld/testsuite/ld-elf/pr26391.out
new file mode 100644 (file)
index 0000000..73654ee
--- /dev/null
@@ -0,0 +1,3 @@
+bar 1
+bar 2
+bar 3
diff --git a/ld/testsuite/ld-elf/pr26391a.c b/ld/testsuite/ld-elf/pr26391a.c
new file mode 100644 (file)
index 0000000..7356d9d
--- /dev/null
@@ -0,0 +1,18 @@
+typedef void (*func_p) (void);
+
+extern func_p bar1_p (void);
+extern func_p bar2_p (void);
+extern func_p bar3_p (void);
+
+int
+main ()
+{
+  func_p f;
+  f = bar1_p ();
+  f ();
+  f = bar2_p ();
+  f ();
+  f = bar3_p ();
+  f ();
+  return 0;
+}
diff --git a/ld/testsuite/ld-elf/pr26391b.c b/ld/testsuite/ld-elf/pr26391b.c
new file mode 100644 (file)
index 0000000..8f716a5
--- /dev/null
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+static void
+bar (void)
+{
+  printf ("bar 1\n");
+}
+
+void *
+bar1_p (void)
+{
+  return bar;
+}
diff --git a/ld/testsuite/ld-elf/pr26391c.c b/ld/testsuite/ld-elf/pr26391c.c
new file mode 100644 (file)
index 0000000..e5bf1c1
--- /dev/null
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+static void
+bar (void)
+{
+  printf ("bar 2\n");
+}
+
+void *
+bar2_p (void)
+{
+  return bar;
+}
diff --git a/ld/testsuite/ld-elf/pr26391d.c b/ld/testsuite/ld-elf/pr26391d.c
new file mode 100644 (file)
index 0000000..6e388f8
--- /dev/null
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+static void
+bar (void)
+{
+  printf ("bar 3\n");
+}
+
+void *
+bar3_p (void)
+{
+  return bar;
+}