From aaa00e84f000a9aa06662c5e6fd7519585bcca36 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Wed, 29 Jul 2020 11:56:38 -0700 Subject: [PATCH] LTO: Ignore undefined symbols without relocation Normally an undefined symbol is treated as a reference. Linker will try to satisfy the reference. This feature is used to bring a symbol definition into output without explicit relocation. If there is no definition nor relocation, linker will remove undefined symbol from symbol table in output (PR ld/4317). But GCC 10 LTO may generate separate debug info files which contain undefined symbols without relocations: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96385 After all LTO IR symbols have been read, if there is a dinition in LTO IR object, there is no relocation, and there is a definition in a shared object, linker may resolve the undefined symbol to the discarded section in LTO IR object. To avoid it, after all LTO IR symbols have been read, skip undefined symbols without relocation. bfd/ PR ld/26324 * elf-bfd.h (elf_link_hash_entry): Add has_reloc_after_lto_all_symbols_read. * elflink.c (_bfd_elf_merge_symbol): After all LTO IR symbols have been read, skip undefined symbols without relocation. (elf_link_add_object_symbols): Set has_reloc_after_lto_all_symbols_read after all LTO IR symbols have been read. ld/ PR ld/26324 * testsuite/ld-plugin/lto.exp: Run ld/26324 test. * testsuite/ld-plugin/pr26324a.c: New file. --- bfd/elf-bfd.h | 4 ++ bfd/elflink.c | 98 +++++++++++++++++++++++++++++++ ld/testsuite/ld-plugin/lto.exp | 5 ++ ld/testsuite/ld-plugin/pr26324a.c | 16 +++++ 4 files changed, 123 insertions(+) create mode 100644 ld/testsuite/ld-plugin/pr26324a.c diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index cd352d2a8e..470e2f7711 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -224,6 +224,10 @@ struct elf_link_hash_entry a strong defined symbol alias. U.ALIAS points to a list of aliases, the definition having is_weakalias clear. */ unsigned int is_weakalias : 1; + /* There is relocation against symbol in the object. NB: It is only + set and used by elf_link_add_object_symbols after all LTO IR symbols + have been read. */ + unsigned int has_reloc_after_lto_all_symbols_read : 1; /* String table index in .dynstr if this is a dynamic symbol. */ unsigned long dynstr_index; diff --git a/bfd/elflink.c b/bfd/elflink.c index 0a7f5bb152..481bfcdbbd 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -1238,6 +1238,17 @@ _bfd_elf_merge_symbol (bfd *abfd, return TRUE; } + /* After all LTO IR symbols have been read, skip all undefined + symbols without relocation. */ + if (info->lto_all_symbols_read + && bfd_is_und_section (sec) + && (abfd->flags & DYNAMIC) == 0 + && !h->has_reloc_after_lto_all_symbols_read) + { + *skip = TRUE; + return TRUE; + } + /* In cases involving weak versioned symbols, we may wind up trying to merge a symbol with itself. Catch that here, to avoid the confusion that results if we try to override a symbol with @@ -4555,6 +4566,93 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) (_("%pB: plugin needed to handle lto object"), abfd); } + /* Normally an undefined symbol is treated as a reference. Linker + will try to satisfy the reference. This feature is used to bring + a symbol definition into output without explicit relocation. If + there is no definition nor relocation, linker will remove undefined + symbol from symbol table in output (PR ld/4317). But GCC 10 LTO + may generate separate debug info files which contain undefined + symbols without relocations: + + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96385 + + After all LTO IR symbols have been read, if there is a dinition in + LTO IR object, there is no relocation, and there is a definition + in a shared object, linker may resolve the undefined symbol to the + discarded section in LTO IR object. To avoid it, after all LTO IR + symbols have been read, skip undefined symbols without relocation. + */ + if (info->lto_all_symbols_read + && !bfd_link_relocatable (info) + && (abfd->flags & DYNAMIC) == 0 + && !just_syms + && extsymcount) + { + int r_sym_shift; + struct elf_link_hash_entry *h; + const char *name; + + if (bed->s->arch_size == 32) + r_sym_shift = 8; + else + r_sym_shift = 32; + + for (s = abfd->sections; s != NULL; s = s->next) + { + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *rel, *relend; + + /* Don't check relocations in excluded sections. */ + if ((s->flags & SEC_RELOC) == 0 + || s->reloc_count == 0 + || (s->flags & SEC_EXCLUDE) != 0 + || ((info->strip == strip_all + || info->strip == strip_debugger) + && (s->flags & SEC_DEBUGGING) != 0)) + continue; + + internal_relocs = _bfd_elf_link_read_relocs (abfd, s, NULL, + NULL, + info->keep_memory); + if (internal_relocs == NULL) + goto error_free_vers; + + rel = internal_relocs; + relend = rel + s->reloc_count; + for ( ; rel < relend; rel++) + { + unsigned long r_symndx = rel->r_info >> r_sym_shift; + + /* Skip local symbols. */ + if (r_symndx < extsymoff) + continue; + + isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, + r_symndx); + if (isym->st_shndx == SHN_UNDEF) + { + name = bfd_elf_string_from_elf_section (abfd, + hdr->sh_link, + isym->st_name); + h = ((struct elf_link_hash_entry *) + bfd_wrapped_link_hash_lookup (abfd, info, name, + TRUE, FALSE, + FALSE)); + if (h != NULL) + { + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + h->has_reloc_after_lto_all_symbols_read = TRUE; + } + } + } + + if (elf_section_data (s)->relocs != internal_relocs) + free (internal_relocs); + } + } + for (isym = isymbuf, isymend = isymbuf + extsymcount; isym < isymend; isym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL)) diff --git a/ld/testsuite/ld-plugin/lto.exp b/ld/testsuite/ld-plugin/lto.exp index cb2973f3a3..80d141282a 100644 --- a/ld/testsuite/ld-plugin/lto.exp +++ b/ld/testsuite/ld-plugin/lto.exp @@ -588,6 +588,11 @@ set lto_run_elf_tests [list \ [list "LTO TLS IE" \ "-O2 -flto -fuse-linker-plugin" "" \ {run-ie.c} "run-ie.exe" "run-ie.out" "" "c"] \ + [list "PR ld/26324" \ + "-O2 -g -flto -fuse-linker-plugin -Wl,-rpath-link,. \ + -Wl,--no-copy-dt-needed-entries -Wl,--no-as-needed" "" \ + {pr26324a.c} "pr26324.exe" "pass.out" "-O2 -g -flto $lto_fat" "c" {} \ + "tmpdir/pr15146c.so"] \ ] run_cc_link_tests $lto_link_tests diff --git a/ld/testsuite/ld-plugin/pr26324a.c b/ld/testsuite/ld-plugin/pr26324a.c new file mode 100644 index 0000000000..5e4e106c11 --- /dev/null +++ b/ld/testsuite/ld-plugin/pr26324a.c @@ -0,0 +1,16 @@ +#include + +extern int xxx; + +int +bar (void) +{ + return xxx; +} + +int +main () +{ + printf ("PASS\n"); + return 0; +} -- 2.26.2