Use GCC LTO wrapper to get real symbols from LTO IR objects
authorH.J. Lu <hjl.tools@gmail.com>
Tue, 11 Feb 2020 03:01:42 +0000 (19:01 -0800)
committerH.J. Lu <hjl.tools@gmail.com>
Tue, 11 Feb 2020 03:01:53 +0000 (19:01 -0800)
GCC LTO wrapper is needed to extract real symbols from LTO IR objects.
This patch does the following:

1. Set up GCC LTO wrapper for each LTO IR object.
2. Run GCC LTO wrapper to get the real object.
3. Extract symbol info from the real object.
4. Cleanup afterwards.

bfd/

PR binutils/25355
* configure.ac (HAVE_EXECUTABLE_SUFFIX): New AC_DEFINE.
(EXECUTABLE_SUFFIX): Likewise.
* config.in: Regenerated.
* configure: Likewise.
* plugin.c (bfd_plugin_close_and_cleanup): Removed.
(plugin_list_entry): Add all_symbols_read, cleanup_handler,
gcc, lto_wrapper, resolution_file, resolution_option, gcc_env,
real_bfd, real_nsyms, real_syms, lto_nsyms and lto_syms.
(get_lto_wrapper): New.
(setup_lto_wrapper_env): Likewise.
(current_plugin): Likewise.
(register_all_symbols_read): Likewise.
(register_cleanup): Likewise.
(get_symbols): Likewise.
(add_input_file): Likewise.
(bfd_plugin_close_and_cleanup): Likewise.
(claim_file): Removed.
(register_claim_file): Set current_plugin->claim_file.
(add_symbols): Make a copy of LTO symbols.  Set lto_nsyms and
lto_syms in current_plugin.
(try_claim): Use current_plugin->claim_file.  Call LTO plugin
all_symbols_read handler.  Copy real symbols to plugin_data.
Call LTO plugin cleanup handler.  Clean up for LTO wrapper.
(try_load_plugin): Don't reuse the previous plugin for LTO
wrapper.  Set up GCC LTO wrapper if possible.  Don't set
plugin_list_iter->claim_file.
(bfd_plugin_canonicalize_symtab): Use real LTO symbols if
possible.
* plugin.h (plugin_data_struct): Add real_bfd, real_nsyms and
real_syms.

ld/

PR binutils/25355
* testsuite/ld-plugin/lto.exp: Run PR binutils/25355 test.
* testsuite/ld-plugin/pr25355.c: New file.
* testsuite/ld-plugin/pr25355.d: Likewise.
* testsuite/lib/ld-lib.exp (run_cc_link_tests): Support compile
only dump.

bfd/ChangeLog
bfd/config.in
bfd/configure
bfd/configure.ac
bfd/plugin.c
bfd/plugin.h
ld/ChangeLog
ld/testsuite/ld-plugin/lto.exp
ld/testsuite/ld-plugin/pr25355.c [new file with mode: 0644]
ld/testsuite/ld-plugin/pr25355.d [new file with mode: 0644]
ld/testsuite/lib/ld-lib.exp

index 083b21fbd97847844e98d9c849786548a0f330f0..fef8bc43004ec2c9e9e06c8f859ad0657db6a0a9 100644 (file)
@@ -1,3 +1,37 @@
+2020-02-10  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR binutils/25355
+       * configure.ac (HAVE_EXECUTABLE_SUFFIX): New AC_DEFINE.
+       (EXECUTABLE_SUFFIX): Likewise.
+       * config.in: Regenerated.
+       * configure: Likewise.
+       * plugin.c (bfd_plugin_close_and_cleanup): Removed.
+       (plugin_list_entry): Add all_symbols_read, cleanup_handler,
+       gcc, lto_wrapper, resolution_file, resolution_option, gcc_env,
+       real_bfd, real_nsyms, real_syms, lto_nsyms and lto_syms.
+       (get_lto_wrapper): New.
+       (setup_lto_wrapper_env): Likewise.
+       (current_plugin): Likewise.
+       (register_all_symbols_read): Likewise.
+       (register_cleanup): Likewise.
+       (get_symbols): Likewise.
+       (add_input_file): Likewise.
+       (bfd_plugin_close_and_cleanup): Likewise.
+       (claim_file): Removed.
+       (register_claim_file): Set current_plugin->claim_file.
+       (add_symbols): Make a copy of LTO symbols.  Set lto_nsyms and
+       lto_syms in current_plugin.
+       (try_claim): Use current_plugin->claim_file.  Call LTO plugin
+       all_symbols_read handler.  Copy real symbols to plugin_data.
+       Call LTO plugin cleanup handler.  Clean up for LTO wrapper.
+       (try_load_plugin): Don't reuse the previous plugin for LTO
+       wrapper.  Set up GCC LTO wrapper if possible.  Don't set
+       plugin_list_iter->claim_file.
+       (bfd_plugin_canonicalize_symtab): Use real LTO symbols if
+       possible.
+       * plugin.h (plugin_data_struct): Add real_bfd, real_nsyms and
+       real_syms.
+
 2020-02-10  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
 
        * elf32-msp430.c (msp430_elf_relax_section): Before relaxing a branch,
index be572969fc04ea4ab36a72e3ebf7b3823c4eb9f6..e1dc0f0c445ba36abe491adb7370527f85b0d4c5 100644 (file)
@@ -18,6 +18,9 @@
    language is requested. */
 #undef ENABLE_NLS
 
+/* Suffix used for executables, if any. */
+#undef EXECUTABLE_SUFFIX
+
 /* Define to 1 if you have the <alloca.h> header file. */
 #undef HAVE_ALLOCA_H
 
@@ -95,6 +98,9 @@
 /* Define to 1 if you have the <dlfcn.h> 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
 
index bcc1a4eaf2fa1753d9f58cf0c5128d5e11d0961c..cca67ee1080eea3076bb42664880062c8886046f 100755 (executable)
 
 
 
+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
index c5bfbd5d129ceb5668cf2af76e0f227cbc5c3846..af4d4b8c1354d7e92a5aa235cd5257f5fb854f41 100644 (file)
@@ -157,6 +157,12 @@ 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
index 537ab603110b88550032cf49d8a7c6a354c3f09a..1edcb57bf3a358a6f01d44c756a3a0bac45a6674 100644 (file)
@@ -69,7 +69,6 @@ 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
@@ -124,13 +123,312 @@ message (int level ATTRIBUTE_UNUSED,
   return LDPS_OK;
 }
 
+struct plugin_list_entry
+{
+  /* These must be initialized for each IR object with LTO wrapper.  */
+  void *handle;
+  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;
+
+  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;
+};
+
+/* 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 (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;
+static struct plugin_list_entry *current_plugin = NULL;
+
 /* Register a claim-file handler. */
-static ld_plugin_claim_file_handler claim_file = NULL;
 
 static enum ld_plugin_status
 register_claim_file (ld_plugin_claim_file_handler handler)
 {
-  claim_file = handler;
+  current_plugin->claim_file = 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;
 }
 
@@ -143,13 +441,50 @@ add_symbols (void * handle,
   struct plugin_data_struct *plugin_data =
     bfd_alloc (abfd, sizeof (plugin_data_struct));
 
-  plugin_data->nsyms = nsyms;
-  plugin_data->syms = syms;
+  if (plugin_data)
+    {
+      struct ld_plugin_symbol *sym_info;
+      char *strtab;
+      size_t sym_info_size, name_length;
+      int i;
+
+      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);
+
+      /* 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;
+       }
+    }
 
   if (nsyms != 0)
     abfd->flags |= HAS_SYMS;
 
-  abfd->tdata.plugin_data = plugin_data;
   return LDPS_OK;
 }
 
@@ -214,26 +549,48 @@ try_claim (bfd *abfd)
   file.handle = abfd;
   if (!bfd_plugin_open_input (abfd, &file))
     return 0;
-  if (claim_file)
-    claim_file (&file, &claimed);
+  if (current_plugin->claim_file)
+    {
+      current_plugin->claim_file (&file, &claimed);
+      if (claimed)
+       {
+         if (current_plugin->all_symbols_read)
+           {
+             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 ();
+               }
+           }
+       }
+
+      if (current_plugin->lto_wrapper)
+       {
+         /* Clean up for LTO wrapper.  */
+         unlink (current_plugin->resolution_file);
+         free (current_plugin->resolution_option);
+       }
+    }
   close (file.fd);
   return claimed;
 }
 
-struct plugin_list_entry
-{
-  void *                        handle;
-  ld_plugin_claim_file_handler  claim_file;
-  struct plugin_list_entry *    next;
-};
-
-static struct plugin_list_entry * plugin_list = NULL;
-
 static int
 try_load_plugin (const char *pname, bfd *abfd, int *has_plugin_p)
 {
   void *plugin_handle = NULL;
-  struct ld_plugin_tv tv[4];
+  struct ld_plugin_tv tv[12];
   int i;
   ld_plugin_onload onload;
   enum ld_plugin_status status;
@@ -241,6 +598,18 @@ try_load_plugin (const char *pname, bfd *abfd, int *has_plugin_p)
 
   *has_plugin_p = 0;
 
+  /* NB: Each object is inddependent.  Reuse the previous plugin from
+     the last LTO wrapper run will lead to wrong LTO data.  */
+  if (current_plugin
+      && current_plugin->handle
+      && current_plugin->lto_wrapper
+      && strcmp (current_plugin->plugin_name, pname) == 0)
+    {
+      dlclose (current_plugin->handle);
+      memset (current_plugin, 0,
+             offsetof (struct plugin_list_entry, next));
+    }
+
   plugin_handle = dlopen (pname, RTLD_NOW);
   if (!plugin_handle)
     {
@@ -259,18 +628,25 @@ try_load_plugin (const char *pname, bfd *abfd, int *has_plugin_p)
            return 0;
 
          register_claim_file (plugin_list_iter->claim_file);
+         current_plugin = plugin_list_iter;
          goto have_claim_file;
        }
+      else if (plugin_list_iter->lto_wrapper
+              && strcmp (plugin_list_iter->plugin_name, pname) == 0)
+       goto have_lto_wrapper;
     }
 
   plugin_list_iter = bfd_malloc (sizeof *plugin_list_iter);
   if (plugin_list_iter == NULL)
     return 0;
-  plugin_list_iter->handle = plugin_handle;
-  plugin_list_iter->claim_file = NULL;
+  memset (plugin_list_iter, 0, sizeof (*plugin_list_iter));
+  plugin_list_iter->plugin_name = pname;
   plugin_list_iter->next = plugin_list;
   plugin_list = plugin_list_iter;
 
+have_lto_wrapper:
+  plugin_list_iter->handle = plugin_handle;
+
   onload = dlsym (plugin_handle, "onload");
   if (!onload)
     return 0;
@@ -287,23 +663,63 @@ try_load_plugin (const char *pname, bfd *abfd, int *has_plugin_p)
   tv[i].tv_tag = LDPT_ADD_SYMBOLS;
   tv[i].tv_u.tv_add_symbols = add_symbols;
 
+  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;
 
+  current_plugin = plugin_list_iter;
+
+  /* LTO plugin will call handler hooks to set up plugin handlers.  */
   status = (*onload)(tv);
 
   if (status != LDPS_OK)
     return 0;
 
-  plugin_list_iter->claim_file = claim_file;
+  if (current_plugin->lto_wrapper
+      && setup_lto_wrapper_env (current_plugin))
+    return 0;
 
 have_claim_file:
   *has_plugin_p = 1;
 
   abfd->plugin_format = bfd_plugin_no;
 
-  if (!claim_file)
+  if (!current_plugin->claim_file)
     return 0;
 
   if (!try_claim (abfd))
@@ -562,7 +978,15 @@ bfd_plugin_canonicalize_symtab (bfd *abfd,
                        SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS);
   static asection fake_common_section
     = BFD_FAKE_SECTION (fake_common_section, NULL, "plug", 0, SEC_IS_COMMON);
-  int i;
+  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;
 
   for (i = 0; i < nsyms; i++)
     {
@@ -587,6 +1011,15 @@ bfd_plugin_canonicalize_symtab (bfd *abfd,
        case LDPK_DEF:
        case LDPK_WEAKDEF:
          s->section = &fake_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;
+               }
          break;
        default:
          BFD_ASSERT (0);
@@ -635,6 +1068,24 @@ 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.  */
index 098bf0845548b6838ba4457203fd693d0bb4afd3..05c3573933dc5929a9472e3a104263a52cf33cdd 100644 (file)
@@ -33,6 +33,9 @@ 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;
 
index c3b5541b963c3491354d0cd80e7c870480b86cd0..57c215fae468976f38458a90d369aa2025863dba 100644 (file)
@@ -1,3 +1,12 @@
+2020-02-10  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR binutils/25355
+       * testsuite/ld-plugin/lto.exp: Run PR binutils/25355 test.
+       * testsuite/ld-plugin/pr25355.c: New file.
+       * testsuite/ld-plugin/pr25355.d: Likewise.
+       * testsuite/lib/ld-lib.exp (run_cc_link_tests): Support compile
+       only dump.
+
 2020-02-07  H.J. Lu  <hongjiu.lu@intel.com>
 
        * testsuite/ld-unique/unique.exp (contains_unique_symbol): Updated.
index 9b03b7b397730955e10808463c75c259e711f874..1b44b0da3fda900518255a18cf9f2a57e8f07841 100644 (file)
@@ -234,6 +234,11 @@ 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 4 7] } {
diff --git a/ld/testsuite/ld-plugin/pr25355.c b/ld/testsuite/ld-plugin/pr25355.c
new file mode 100644 (file)
index 0000000..99f01fb
--- /dev/null
@@ -0,0 +1,2 @@
+int nm_test_var;
+int nm_test_var2 = 1234;
diff --git a/ld/testsuite/ld-plugin/pr25355.d b/ld/testsuite/ld-plugin/pr25355.d
new file mode 100644 (file)
index 0000000..98d10ab
--- /dev/null
@@ -0,0 +1,4 @@
+#...
+[0-9a-f]+ B _?nm_test_var
+[0-9a-f]+ D _?nm_test_var2
+#pass
index 08e2d6978af1f45fa647bea3456500468462ef21..015eda6eb971d6f97905bfa0d55880a8f2131245 100644 (file)
@@ -928,6 +928,7 @@ proc run_cc_link_tests { ldtests } {
 
        if { $binfile eq "tmpdir/" } {
            # compile only
+           set binfile $objfile
        } elseif { [regexp ".*\\.a$" $binfile] } {
            if { ![ar_simple_create $ar $ldflags $binfile "$objfiles"] } {
                set failed 1