aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog11
-rw-r--r--bfd/elflink.c207
-rw-r--r--include/ChangeLog5
-rw-r--r--include/bfdlink.h3
-rw-r--r--ld/ChangeLog17
-rw-r--r--ld/NEWS2
-rw-r--r--ld/emultempl/elf.em4
-rw-r--r--ld/ld.texi6
-rw-r--r--ld/lexsup.c4
-rw-r--r--ld/testsuite/ld-elf/elf.exp121
-rw-r--r--ld/testsuite/ld-elf/pr26391.nd7
-rw-r--r--ld/testsuite/ld-elf/pr26391.out3
-rw-r--r--ld/testsuite/ld-elf/pr26391a.c18
-rw-r--r--ld/testsuite/ld-elf/pr26391b.c13
-rw-r--r--ld/testsuite/ld-elf/pr26391c.c13
-rw-r--r--ld/testsuite/ld-elf/pr26391d.c13
16 files changed, 406 insertions, 41 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 19415d6..4f0faa5 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 0e339f3..b693729 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -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;
}
/* Initialize COOKIE for input bfd ABFD. */
diff --git a/include/ChangeLog b/include/ChangeLog
index c8a90cf..38baf59 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -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
diff --git a/include/bfdlink.h b/include/bfdlink.h
index 3badfbdb..55020e3 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -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. */
diff --git a/ld/ChangeLog b/ld/ChangeLog
index d81ebcc..8d63f66 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -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 6953481..e4ae43b 100644
--- 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.
diff --git a/ld/emultempl/elf.em b/ld/emultempl/elf.em
index 356f345..59eed70 100644
--- a/ld/emultempl/elf.em
+++ b/ld/emultempl/elf.em
@@ -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;
diff --git a/ld/ld.texi b/ld/ld.texi
index 7d961c3..ee592df 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -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
diff --git a/ld/lexsup.c b/ld/lexsup.c
index b9cc8a1..b8f0667 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -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"));
}
diff --git a/ld/testsuite/ld-elf/elf.exp b/ld/testsuite/ld-elf/elf.exp
index c0d67d8..f2ff039 100644
--- a/ld/testsuite/ld-elf/elf.exp
+++ b/ld/testsuite/ld-elf/elf.exp
@@ -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
index 0000000..8dd48d9
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr26391.nd
@@ -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
index 0000000..73654ee
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr26391.out
@@ -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
index 0000000..7356d9d
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr26391a.c
@@ -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
index 0000000..8f716a5
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr26391b.c
@@ -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
index 0000000..e5bf1c1
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr26391c.c
@@ -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
index 0000000..6e388f8
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr26391d.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+static void
+bar (void)
+{
+ printf ("bar 3\n");
+}
+
+void *
+bar3_p (void)
+{
+ return bar;
+}