diff options
-rw-r--r-- | bfd/ChangeLog | 11 | ||||
-rw-r--r-- | bfd/elflink.c | 207 | ||||
-rw-r--r-- | include/ChangeLog | 5 | ||||
-rw-r--r-- | include/bfdlink.h | 3 | ||||
-rw-r--r-- | ld/ChangeLog | 17 | ||||
-rw-r--r-- | ld/NEWS | 2 | ||||
-rw-r--r-- | ld/emultempl/elf.em | 4 | ||||
-rw-r--r-- | ld/ld.texi | 6 | ||||
-rw-r--r-- | ld/lexsup.c | 4 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/elf.exp | 121 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/pr26391.nd | 7 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/pr26391.out | 3 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/pr26391a.c | 18 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/pr26391b.c | 13 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/pr26391c.c | 13 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/pr26391d.c | 13 |
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 @@ -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; @@ -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; +} |