From: H.J. Lu Date: Fri, 20 Mar 2020 10:55:17 +0000 (-0700) Subject: plugin: Don't invoke LTO-wrapper X-Git-Url: http://git.efficios.com/?a=commitdiff_plain;h=3d98c46092341c1373d960d0a66ca502d5b7ee7f;hp=c3a1714ce7806002726a60c0db09371425fe3097;p=deliverable%2Fbinutils-gdb.git plugin: Don't invoke LTO-wrapper Don't invoke LTO-wrapper since the LTO wrapper approach is not only slow but also unreliable. For GCC 10 or newer, LDPT_ADD_SYMBOLS_V2 will be used. bfd/ * configure.ac (HAVE_EXECUTABLE_SUFFIX): Removed. (EXECUTABLE_SUFFIX): Likewise. * config.in: Regenerated. * configure: Likewise. * plugin.c (bfd_plugin_close_and_cleanup): Defined as _bfd_generic_close_and_cleanup. (plugin_list_entry): Remove resolution_file, resolution_option, real_bfd, real_nsyms, real_syms, lto_nsyms, lto_syms, gcc, lto_wrapper, gcc_env and initialized, (need_lto_wrapper_p): Removed. (get_lto_wrapper): Likewise. (setup_lto_wrapper_env): Likewise. (register_all_symbols_read): Likewise. (egister_cleanup): Likewise. (get_symbols): Likewise. (add_input_file): Likewise. (bfd_plugin_set_program_name): Remove need_lto_wrapper. (add_symbols): Updated. (try_claim): Likewise. (try_load_plugin): Likewise. (bfd_plugin_canonicalize_symtab): Likewise. * plugin.h (bfd_plugin_set_program_name): Remove int argument. (plugin_data_struct): Remove real_bfd, real_nsyms and real_syms. binutils/ * ar.c (main): Update bfd_plugin_set_program_name call. * nm.c (main): Likewise. ld/ * testsuite/ld-plugin/lto.exp (lto_link_tests): Run PR ld/25355 test only for GCC 10 or newer. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 47ae881c25..62e564e1dc 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,29 @@ +2020-03-20 H.J. Lu + + * configure.ac (HAVE_EXECUTABLE_SUFFIX): Removed. + (EXECUTABLE_SUFFIX): Likewise. + * config.in: Regenerated. + * configure: Likewise. + * plugin.c (bfd_plugin_close_and_cleanup): Defined as + _bfd_generic_close_and_cleanup. + (plugin_list_entry): Remove resolution_file, resolution_option, + real_bfd, real_nsyms, real_syms, lto_nsyms, lto_syms, gcc, + lto_wrapper, gcc_env and initialized, + (need_lto_wrapper_p): Removed. + (get_lto_wrapper): Likewise. + (setup_lto_wrapper_env): Likewise. + (register_all_symbols_read): Likewise. + (egister_cleanup): Likewise. + (get_symbols): Likewise. + (add_input_file): Likewise. + (bfd_plugin_set_program_name): Remove need_lto_wrapper. + (add_symbols): Updated. + (try_claim): Likewise. + (try_load_plugin): Likewise. + (bfd_plugin_canonicalize_symtab): Likewise. + * plugin.h (bfd_plugin_set_program_name): Remove int argument. + (plugin_data_struct): Remove real_bfd, real_nsyms and real_syms. + 2020-03-19 H.J. Lu PR binutils/25640 diff --git a/bfd/config.in b/bfd/config.in index e1dc0f0c44..be572969fc 100644 --- a/bfd/config.in +++ b/bfd/config.in @@ -18,9 +18,6 @@ language is requested. */ #undef ENABLE_NLS -/* Suffix used for executables, if any. */ -#undef EXECUTABLE_SUFFIX - /* Define to 1 if you have the header file. */ #undef HAVE_ALLOCA_H @@ -98,9 +95,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H -/* Does the platform use an executable suffix? */ -#undef HAVE_EXECUTABLE_SUFFIX - /* Define to 1 if you have the `fcntl' function. */ #undef HAVE_FCNTL diff --git a/bfd/configure b/bfd/configure index 0fdd81d897..a000929b4e 100755 --- a/bfd/configure +++ b/bfd/configure @@ -12813,16 +12813,6 @@ fi -if test -n "$EXEEXT"; then - -$as_echo "#define HAVE_EXECUTABLE_SUFFIX 1" >>confdefs.h - -fi - -cat >>confdefs.h <<_ACEOF -#define EXECUTABLE_SUFFIX "${EXEEXT}" -_ACEOF - host64=false target64=false diff --git a/bfd/configure.ac b/bfd/configure.ac index 96684dbf65..84d07688ad 100644 --- a/bfd/configure.ac +++ b/bfd/configure.ac @@ -157,12 +157,6 @@ AM_MAINTAINER_MODE AM_CONDITIONAL(GENINSRC_NEVER, false) AM_INSTALL_LIBBFD AC_EXEEXT -if test -n "$EXEEXT"; then - AC_DEFINE(HAVE_EXECUTABLE_SUFFIX, 1, - [Does the platform use an executable suffix?]) -fi -AC_DEFINE_UNQUOTED(EXECUTABLE_SUFFIX, "${EXEEXT}", - [Suffix used for executables, if any.]) host64=false target64=false diff --git a/bfd/plugin.c b/bfd/plugin.c index 13549d24e7..48387fa53e 100644 --- a/bfd/plugin.c +++ b/bfd/plugin.c @@ -69,6 +69,7 @@ dlerror (void) #endif /* !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H) */ +#define bfd_plugin_close_and_cleanup _bfd_generic_close_and_cleanup #define bfd_plugin_bfd_free_cached_info _bfd_generic_bfd_free_cached_info #define bfd_plugin_new_section_hook _bfd_generic_new_section_hook #define bfd_plugin_get_section_contents _bfd_generic_get_section_contents @@ -129,196 +130,20 @@ struct plugin_list_entry ld_plugin_claim_file_handler claim_file; ld_plugin_all_symbols_read_handler all_symbols_read; ld_plugin_all_symbols_read_handler cleanup_handler; - char *resolution_file; - char *resolution_option; - bfd *real_bfd; - long real_nsyms; - asymbol **real_syms; - int lto_nsyms; - const struct ld_plugin_symbol *lto_syms; bfd_boolean has_symbol_type; struct plugin_list_entry *next; /* These can be reused for all IR objects. */ const char *plugin_name; - char *gcc; - char *lto_wrapper; - char *gcc_env; - bfd_boolean initialized; }; static const char *plugin_program_name; -static int need_lto_wrapper_p; void -bfd_plugin_set_program_name (const char *program_name, - int need_lto_wrapper) +bfd_plugin_set_program_name (const char *program_name) { plugin_program_name = program_name; - need_lto_wrapper_p = need_lto_wrapper; -} - -/* Use GCC LTO wrapper to covert LTO IR object to the real object. */ - -static bfd_boolean -get_lto_wrapper (struct plugin_list_entry *plugin) -{ - struct stat st; - const char *real_name; - const char *base_name; - size_t length; - const char *target_start = NULL; - const char *target_end = NULL; - size_t target_length = 0; - char *gcc_name; - char *wrapper_name; - char *p; - char dir_seperator = '\0'; - char *resolution_file; - - if (!need_lto_wrapper_p) - return FALSE; - - if (plugin->initialized) - { - if (plugin->lto_wrapper) - { - resolution_file = make_temp_file (".res"); - if (resolution_file) - { - plugin->resolution_file = resolution_file; - plugin->resolution_option = concat ("-fresolution=", - resolution_file, NULL); - return TRUE; - } - else - { - /* Something is wrong. Give up. */ - free (plugin->gcc); - free (plugin->lto_wrapper); - free (plugin->gcc_env); - plugin->gcc = NULL; - plugin->gcc_env = NULL; - plugin->lto_wrapper = NULL; - } - } - - return FALSE; - } - - plugin->initialized = TRUE; - - /* Check for PREFIX/libexec/gcc/TARGET/VERSION/liblto_plugin.so. */ - real_name = lrealpath (plugin->plugin_name); - base_name = lbasename (real_name); - - /* The directory length in plugin pathname. */ - length = base_name - real_name; - - /* Skip if there is no PREFIX. */ - if (!length) - return FALSE; - - p = (char *) real_name + length - 1; - if (IS_DIR_SEPARATOR (*p)) - { - int level = 0; - for (; p != real_name; p--) - if (IS_DIR_SEPARATOR (*p)) - { - level++; - if (level == 2) - target_end = p; - else if (level == 3) - { - target_start = p + 1; - target_length = target_end - target_start; - } - else if (level == 5) - { - dir_seperator = *p; - break; - } - } - } - - /* Skip if there is no TARGET nor PREFIX. */ - if (!target_length || !dir_seperator) - return FALSE; - -#ifdef HAVE_EXECUTABLE_SUFFIX -# define GCC_EXECUTABLE "gcc" EXECUTABLE_SUFFIX -# define LTO_WRAPPER_EXECUTABLE "lto-wrapper" EXECUTABLE_SUFFIX -#else -# define GCC_EXECUTABLE "gcc" -# define LTO_WRAPPER_EXECUTABLE "lto-wrapper" -#endif - gcc_name = bfd_malloc (length + target_length - + sizeof (GCC_EXECUTABLE)); - if (gcc_name == NULL) - return FALSE; - memcpy (gcc_name, real_name, length); - - /* Get PREFIX/bin/. */ - p += gcc_name - real_name; - memcpy (p + 1, "bin", 3); - p[4] = dir_seperator; - - /* Try PREFIX/bin/TARGET-gcc first. */ - memcpy (p + 5, target_start, target_length); - p[5 + target_length] = '-'; - memcpy (p + 5 + target_length + 1, GCC_EXECUTABLE, - sizeof (GCC_EXECUTABLE)); - if (stat (gcc_name, &st) != 0 || !S_ISREG (st.st_mode)) - { - /* Then try PREFIX/bin/gcc. */ - memcpy (p + 5, GCC_EXECUTABLE, sizeof (GCC_EXECUTABLE)); - if (stat (gcc_name, &st) != 0 || !S_ISREG (st.st_mode)) - { - free (gcc_name); - return FALSE; - } - } - - /* lto-wrapper should be in the same directory with LTO plugin. */ - wrapper_name = bfd_malloc (length + sizeof (LTO_WRAPPER_EXECUTABLE)); - if (wrapper_name == NULL) - { - free (gcc_name); - return FALSE; - } - memcpy (wrapper_name, real_name, length); - memcpy (wrapper_name + length, LTO_WRAPPER_EXECUTABLE, - sizeof (LTO_WRAPPER_EXECUTABLE)); - if (stat (wrapper_name, &st) == 0 && S_ISREG (st.st_mode)) - { - resolution_file = make_temp_file (".res"); - if (resolution_file) - { - plugin->gcc = gcc_name; - plugin->lto_wrapper = wrapper_name; - plugin->gcc_env = concat ("COLLECT_GCC=", gcc_name, NULL); - plugin->resolution_file = resolution_file; - plugin->resolution_option = concat ("-fresolution=", - resolution_file, NULL); - return TRUE; - } - } - - free (gcc_name); - free (wrapper_name); - return FALSE; -} - -/* Set environment variables for GCC LTO wrapper to covert LTO IR - object to the real object. */ - -static int -setup_lto_wrapper_env (struct plugin_list_entry *plugin) -{ - return (putenv (plugin->gcc_env) - || putenv ("COLLECT_GCC_OPTIONS=")); } static struct plugin_list_entry *plugin_list = NULL; @@ -333,119 +158,6 @@ register_claim_file (ld_plugin_claim_file_handler handler) return LDPS_OK; } -/* Register an all-symbols-read handler. */ - -static enum ld_plugin_status -register_all_symbols_read (ld_plugin_all_symbols_read_handler handler) -{ - current_plugin->all_symbols_read = handler; - return LDPS_OK; -} - -/* Register a cleanup handler. */ - -static enum ld_plugin_status -register_cleanup (ld_plugin_all_symbols_read_handler handler) -{ - current_plugin->cleanup_handler = handler; - return LDPS_OK; -} - -/* Get the symbol resolution info for a plugin-claimed input file. */ - -static enum ld_plugin_status -get_symbols (const void *handle ATTRIBUTE_UNUSED, int nsyms, - struct ld_plugin_symbol *syms) -{ - if (syms) - { - int n; - for (n = 0; n < nsyms; n++) - { - switch (syms[n].def) - { - default: - BFD_ASSERT (0); - break; - case LDPK_UNDEF: - case LDPK_WEAKUNDEF: - syms[n].resolution = LDPR_UNDEF; - break; - case LDPK_DEF: - case LDPK_WEAKDEF: - case LDPK_COMMON: - /* Tell plugin that LTO symbol has references from regular - object code. */ - syms[n].resolution = LDPR_PREVAILING_DEF; - break; - } - } - } - - return LDPS_OK; -} - -/* Add a new (real) input file generated by a plugin. */ - -static enum ld_plugin_status -add_input_file (const char *pathname) -{ - /* Get symbols from the real LTO object. */ - char **matching; - long real_symsize; - long real_nsyms; - asymbol **real_syms; - int lto_nsyms; - bfd_boolean lto_symbol_found = FALSE; - const struct ld_plugin_symbol *lto_syms; - bfd *rbfd; - int i, j; - - rbfd = bfd_openr (pathname, NULL); - if (!bfd_check_format_matches (rbfd, bfd_object, &matching)) - BFD_ASSERT (0); - - real_symsize = bfd_get_symtab_upper_bound (rbfd); - if (real_symsize < 0) - BFD_ASSERT (0); - - real_syms = (asymbol **) bfd_malloc (real_symsize); - if (real_syms) - { - real_nsyms = bfd_canonicalize_symtab (rbfd, real_syms); - if (real_nsyms < 0) - BFD_ASSERT (0); - - /* NB: LTO plugin may generate more than one real object from one - LTO IR object. We use the one which contains LTO symbols. */ - lto_syms = current_plugin->lto_syms; - lto_nsyms = current_plugin->lto_nsyms; - for (i = 0; i < lto_nsyms; i++) - for (j = 0; j < real_nsyms; j++) - if (real_syms[j]->name - && strcmp (lto_syms[i].name, real_syms[j]->name) == 0) - { - lto_symbol_found = TRUE; - break; - } - } - - if (lto_symbol_found) - { - current_plugin->real_nsyms = real_nsyms; - current_plugin->real_syms = real_syms; - /* NB: We can't close RBFD which own the real symbol info. */ - current_plugin->real_bfd = rbfd; - } - else - { - bfd_close (rbfd); - free (real_syms); - } - - return LDPS_OK; -} - static enum ld_plugin_status add_symbols (void * handle, int nsyms, @@ -455,52 +167,16 @@ add_symbols (void * handle, struct plugin_data_struct *plugin_data = bfd_alloc (abfd, sizeof (plugin_data_struct)); - if (plugin_data) - { - struct ld_plugin_symbol *sym_info; - char *strtab; - size_t sym_info_size, name_length; - int i; - - memset (plugin_data, 0, sizeof (*plugin_data)); - - abfd->tdata.plugin_data = plugin_data; - - /* NB: LTO symbols are owned by LTO plugin. Create a copy so - that we can use it in bfd_plugin_canonicalize_symtab. */ - sym_info_size = nsyms * sizeof (*syms); + if (!plugin_data) + return LDPS_ERR; - /* Allocate a string table */ - for (i = 0; i < nsyms; i++) - sym_info_size += strlen (syms[i].name) + 1; - - sym_info = bfd_alloc (abfd, sym_info_size); - if (sym_info) - { - /* Copy symbol table. */ - memcpy (sym_info, syms, nsyms * sizeof (*syms)); - - /* Copy symbol names in symbol table. */ - strtab = (char *) (sym_info + nsyms); - for (i = 0; i < nsyms; i++) - { - name_length = strlen (syms[i].name); - memcpy (strtab, syms[i].name, name_length + 1); - sym_info[i].name = strtab; - strtab += name_length + 1; - } - - plugin_data->nsyms = nsyms; - plugin_data->syms = sym_info; - - current_plugin->lto_nsyms = nsyms; - current_plugin->lto_syms = sym_info; - } - } + plugin_data->nsyms = nsyms; + plugin_data->syms = syms; if (nsyms != 0) abfd->flags |= HAS_SYMS; + abfd->tdata.plugin_data = plugin_data; return LDPS_OK; } @@ -567,42 +243,9 @@ try_claim (bfd *abfd) && current_plugin->claim_file) { current_plugin->claim_file (&file, &claimed); - if (claimed) - { - if (current_plugin->all_symbols_read - && !current_plugin->has_symbol_type) - { - struct plugin_data_struct *plugin_data - = abfd->tdata.plugin_data; - if (plugin_data) - { - /* Get real symbols from LTO wrapper. */ - current_plugin->all_symbols_read (); - - /* Copy real symbols to plugin_data. */ - plugin_data->real_bfd = current_plugin->real_bfd; - plugin_data->real_nsyms = current_plugin->real_nsyms; - plugin_data->real_syms = current_plugin->real_syms; - - /* Clean up LTO plugin. */ - if (current_plugin->cleanup_handler) - current_plugin->cleanup_handler (); - } - } - } - close (file.fd); } - if (current_plugin->lto_wrapper) - { - /* Clean up for LTO wrapper. NB: Resolution file and option - have been created regardless if an IR object is claimed or - not. */ - unlink (current_plugin->resolution_file); - free (current_plugin->resolution_option); - } - return claimed; } @@ -612,7 +255,7 @@ try_load_plugin (const char *pname, bfd *abfd, bfd_boolean build_list_p) { void *plugin_handle; - struct ld_plugin_tv tv[13]; + struct ld_plugin_tv tv[5]; int i; ld_plugin_onload onload; enum ld_plugin_status status; @@ -679,41 +322,6 @@ try_load_plugin (const char *pname, tv[i].tv_tag = LDPT_ADD_SYMBOLS_V2; tv[i].tv_u.tv_add_symbols = add_symbols_v2; - if (get_lto_wrapper (plugin_list_iter)) - { - ++i; - tv[i].tv_tag = LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK; - tv[i].tv_u.tv_register_all_symbols_read = register_all_symbols_read; - - ++i; - tv[i].tv_tag = LDPT_REGISTER_CLEANUP_HOOK; - tv[i].tv_u.tv_register_cleanup = register_cleanup; - - ++i; - tv[i].tv_tag = LDPT_GET_SYMBOLS; - tv[i].tv_u.tv_get_symbols = get_symbols; - - ++i; - tv[i].tv_tag = LDPT_GET_SYMBOLS_V2; - tv[i].tv_u.tv_get_symbols = get_symbols; - - ++i; - tv[i].tv_tag = LDPT_OPTION; - tv[i].tv_u.tv_string = plugin_list_iter->lto_wrapper; - - ++i; - tv[i].tv_tag = LDPT_OPTION; - tv[i].tv_u.tv_string = plugin_list_iter->resolution_option; - - ++i; - tv[i].tv_tag = LDPT_LINKER_OUTPUT; - tv[i].tv_u.tv_val = LDPO_EXEC; - - ++i; - tv[i].tv_tag = LDPT_ADD_INPUT_FILE; - tv[i].tv_u.tv_add_input_file = add_input_file; - } - ++i; tv[i].tv_tag = LDPT_NULL; tv[i].tv_u.tv_val = 0; @@ -724,10 +332,6 @@ try_load_plugin (const char *pname, if (status != LDPS_OK) goto short_circuit; - if (current_plugin->lto_wrapper - && setup_lto_wrapper_env (current_plugin)) - goto short_circuit; - abfd->plugin_format = bfd_plugin_no; if (!current_plugin->claim_file) @@ -1002,15 +606,7 @@ bfd_plugin_canonicalize_symtab (bfd *abfd, SEC_ALLOC); static asection fake_common_section = BFD_FAKE_SECTION (fake_common_section, NULL, "plug", 0, SEC_IS_COMMON); - int i, j; - long real_nsyms; - asymbol **real_syms; - - real_syms = plugin_data->real_syms; - if (real_syms) - real_nsyms = plugin_data->real_nsyms; - else - real_nsyms = 0; + int i; for (i = 0; i < nsyms; i++) { @@ -1050,18 +646,7 @@ bfd_plugin_canonicalize_symtab (bfd *abfd, break; } else - { - s->section = &fake_text_section; - if (real_nsyms) - /* Use real LTO symbols if possible. */ - for (j = 0; j < real_nsyms; j++) - if (real_syms[j]->name - && strcmp (syms[i].name, real_syms[j]->name) == 0) - { - s->section = real_syms[j]->section; - break; - } - } + s->section = &fake_text_section; break; default: BFD_ASSERT (0); @@ -1110,24 +695,6 @@ bfd_plugin_sizeof_headers (bfd *a ATTRIBUTE_UNUSED, return 0; } -static bfd_boolean -bfd_plugin_close_and_cleanup (bfd *abfd) -{ - struct plugin_data_struct *plugin_data; - - if (abfd->format != bfd_archive - && (plugin_data = abfd->tdata.plugin_data)) - { - if (plugin_data->real_bfd) - bfd_close (plugin_data->real_bfd); - - if (plugin_data->real_syms) - free (plugin_data->real_syms); - } - - return _bfd_generic_close_and_cleanup (abfd); -} - const bfd_target plugin_vec = { "plugin", /* Name. */ diff --git a/bfd/plugin.h b/bfd/plugin.h index af5d1f4cfa..075532dca0 100644 --- a/bfd/plugin.h +++ b/bfd/plugin.h @@ -21,7 +21,7 @@ #ifndef _PLUGIN_H_ #define _PLUGIN_H_ -void bfd_plugin_set_program_name (const char *, int); +void bfd_plugin_set_program_name (const char *); int bfd_plugin_open_input (bfd *, struct ld_plugin_input_file *); void bfd_plugin_set_plugin (const char *); bfd_boolean bfd_plugin_target_p (const bfd_target *); @@ -33,9 +33,6 @@ typedef struct plugin_data_struct { int nsyms; const struct ld_plugin_symbol *syms; - bfd *real_bfd; - long real_nsyms; - asymbol **real_syms; } plugin_data_struct; diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 9b33199634..95761e07e7 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,8 @@ +2020-03-20 H.J. Lu + + * ar.c (main): Update bfd_plugin_set_program_name call. + * nm.c (main): Likewise. + 2020-03-19 Nick Clifton PR 25676 diff --git a/binutils/ar.c b/binutils/ar.c index 35dd51e04a..1057db9980 100644 --- a/binutils/ar.c +++ b/binutils/ar.c @@ -725,7 +725,7 @@ main (int argc, char **argv) xmalloc_set_program_name (program_name); bfd_set_error_program_name (program_name); #if BFD_SUPPORTS_PLUGINS - bfd_plugin_set_program_name (program_name, 0); + bfd_plugin_set_program_name (program_name); #endif expandargv (&argc, &argv); diff --git a/binutils/nm.c b/binutils/nm.c index 5b386592a6..0ee3f88386 100644 --- a/binutils/nm.c +++ b/binutils/nm.c @@ -1701,7 +1701,7 @@ main (int argc, char **argv) xmalloc_set_program_name (program_name); bfd_set_error_program_name (program_name); #if BFD_SUPPORTS_PLUGINS - bfd_plugin_set_program_name (program_name, 1); + bfd_plugin_set_program_name (program_name); #endif START_PROGRESS (program_name, 0); diff --git a/ld/ChangeLog b/ld/ChangeLog index 16159d43f6..16c8b8b069 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,8 @@ +2020-03-20 H.J. Lu + + * testsuite/ld-plugin/lto.exp (lto_link_tests): Run PR ld/25355 + test only for GCC 10 or newer. + 2020-03-20 Alan Modra * testplug.c (parse_symdefstr): Use %hhi to read sym->def, and diff --git a/ld/testsuite/ld-plugin/lto.exp b/ld/testsuite/ld-plugin/lto.exp index 31da465d00..8ffc03f01a 100644 --- a/ld/testsuite/ld-plugin/lto.exp +++ b/ld/testsuite/ld-plugin/lto.exp @@ -234,13 +234,18 @@ set lto_link_tests [list \ [list "Build pr24406-2b.o" \ "" "-O2 -fno-lto" \ {pr24406-2b.c}] \ - [list "pr25355.o" \ - "" \ - "-flto -fno-common $lto_no_fat" \ - {pr25355.c} \ - [list [list "nm" "$plug_opt" "pr25355.d"]]] \ ] +if { [at_least_gcc_version 10 0] } { + set lto_link_tests [concat $lto_link_tests [list \ + [list "pr25355.o" \ + "" \ + "-flto -fno-common $lto_no_fat" \ + {pr25355.c} \ + [list [list "nm" "$plug_opt" "pr25355.d"]]] \ + ]] +} + if { [at_least_gcc_version 4 7] } { set lto_link_tests [concat $lto_link_tests [list \ [list "Compile PR ld/12942 (1)" \