From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pg1-x52a.google.com (mail-pg1-x52a.google.com [IPv6:2607:f8b0:4864:20::52a]) by sourceware.org (Postfix) with ESMTPS id C3EDC395C86F for ; Wed, 9 Sep 2020 16:20:28 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org C3EDC395C86F Received: by mail-pg1-x52a.google.com with SMTP id f2so401986pgd.3 for ; Wed, 09 Sep 2020 09:20:28 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=sftLSD8JXwnmiWVx0ckwjvEqRxJMTCSTZ5BukVnnhzU=; b=Y9JTtJpi1+s205n9xkAe308ahhML+jLQj4v1s/bpzLVZnxWbbYu8b++UHMWdv/xpEj p854Vgva35XJvzRDICieYBc+uDFf+XzfWS8M4NThWTt+56aehOkm1HwtlTT6IY6Uv6+p RZLWVIJWEFP6Sf1zhzhn+nQAqillDEFN0/46/9Me+SYx+hf5f1e2SYZoEy23zhFltWuj tBw91g1i0bL45Zi/vkjbOwh4KE8LaOtS9Tk6GmiS+Pd3LsZCpm66wPWs68ZHOSx4RDmR WWGabjK3ZNXIIISMBsOvPLRGqdrQD6dSSoLfYfXMuNfNmPKbVUGqiW5GxSjwT/KTPACc u9Sg== X-Gm-Message-State: AOAM531DtzYCM2YkITOwvn6f7lSYb+ucTYG0hNA8A5dUg0aRDwwdNbBQ e/kh1lP/kc1IDiWkMcba5hcTK2Atumg= X-Google-Smtp-Source: ABdhPJyTc25DfFAiU2BzIu0FaAFtYjaOazDGKqBzrIAbfG1MD5kTH3pfkb9daW6XO97LkY47nD2w4A== X-Received: by 2002:a65:55c6:: with SMTP id k6mr1162051pgs.49.1599668427054; Wed, 09 Sep 2020 09:20:27 -0700 (PDT) Received: from gnu-cfl-2.localdomain (c-69-181-90-243.hsd1.ca.comcast.net. [69.181.90.243]) by smtp.gmail.com with ESMTPSA id z7sm3297076pfj.75.2020.09.09.09.20.26 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 09 Sep 2020 09:20:26 -0700 (PDT) Received: from gnu-cfl-2.localdomain (localhost [IPv6:::1]) by gnu-cfl-2.localdomain (Postfix) with ESMTP id B06D81A0117 for ; Wed, 9 Sep 2020 09:20:25 -0700 (PDT) From: "H.J. Lu" To: binutils@sourceware.org Subject: [PATCH] elf: Add -z unique-symbol to avoid duplicated local symbol names Date: Wed, 9 Sep 2020 09:20:25 -0700 Message-Id: <20200909162025.391535-1-hjl.tools@gmail.com> X-Mailer: git-send-email 2.26.2 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-12.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 09 Sep 2020 16:20:33 -0000 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. --- bfd/elflink.c | 207 +++++++++++++++++++++++++------- include/bfdlink.h | 3 + ld/NEWS | 2 + ld/emultempl/elf.em | 4 + ld/ld.texi | 6 + ld/lexsup.c | 4 + ld/testsuite/ld-elf/elf.exp | 121 +++++++++++++++++++ ld/testsuite/ld-elf/pr26391.nd | 7 ++ ld/testsuite/ld-elf/pr26391.out | 3 + ld/testsuite/ld-elf/pr26391a.c | 18 +++ ld/testsuite/ld-elf/pr26391b.c | 13 ++ ld/testsuite/ld-elf/pr26391c.c | 13 ++ ld/testsuite/ld-elf/pr26391d.c | 13 ++ 13 files changed, 373 insertions(+), 41 deletions(-) create mode 100644 ld/testsuite/ld-elf/pr26391.nd create mode 100644 ld/testsuite/ld-elf/pr26391.out create mode 100644 ld/testsuite/ld-elf/pr26391a.c create mode 100644 ld/testsuite/ld-elf/pr26391b.c create mode 100644 ld/testsuite/ld-elf/pr26391c.c create mode 100644 ld/testsuite/ld-elf/pr26391d.c diff --git a/bfd/elflink.c b/bfd/elflink.c index 0e339f3c1e..b6937293e8 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/bfdlink.h b/include/bfdlink.h index 3badfbdb19..55020e31f4 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/NEWS b/ld/NEWS index 695348141b..e4ae43b257 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 356f34538b..59eed707ea 100644 --- a/ld/emultempl/elf.em +++ b/ld/emultempl/elf.em @@ -751,6 +751,10 @@ fragment < + +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 0000000000..e5bf1c108d --- /dev/null +++ b/ld/testsuite/ld-elf/pr26391c.c @@ -0,0 +1,13 @@ +#include + +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 0000000000..6e388f8995 --- /dev/null +++ b/ld/testsuite/ld-elf/pr26391d.c @@ -0,0 +1,13 @@ +#include + +static void +bar (void) +{ + printf ("bar 3\n"); +} + +void * +bar3_p (void) +{ + return bar; +} -- 2.26.2