ld: Add -plugin-save-temps

Message ID 20240210134217.108537-1-hjl.tools@gmail.com
State Committed
Headers
Series ld: Add -plugin-save-temps |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 fail Patch failed to apply

Commit Message

H.J. Lu Feb. 10, 2024, 1:42 p.m. UTC
  Add -plugin-save-temps to store plugin intermediate files permanently.
It can be used to exam the final input object files generated from IR
inputs.

	* NEWS: Mention -plugin-save-temps.
	* ld.h (ld_config_type): Add plugin_save_temps.
	* ld.texi: Document -plugin-save-temps.
	* ldlex.h (option_values): Add OPTION_PLUGIN_SAVE_TEMPS.
	* lexsup.c (ld_options): Add -plugin-save-temps.
	(parse_args): Handle OPTION_PLUGIN_SAVE_TEMPS.
	* plugin.c (plugin_call_cleanup): Don't call plugin
	cleanup_handler for -plugin-save-temps.
---
 ld/NEWS     |  2 ++
 ld/ld.h     |  3 +++
 ld/ld.texi  |  4 ++++
 ld/ldlex.h  |  1 +
 ld/lexsup.c |  6 ++++++
 ld/plugin.c | 19 +++++++++++--------
 6 files changed, 27 insertions(+), 8 deletions(-)
  

Comments

H.J. Lu Feb. 16, 2024, 12:17 p.m. UTC | #1
On Sat, Feb 10, 2024 at 5:42 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> Add -plugin-save-temps to store plugin intermediate files permanently.
> It can be used to exam the final input object files generated from IR
> inputs.
>
>         * NEWS: Mention -plugin-save-temps.
>         * ld.h (ld_config_type): Add plugin_save_temps.
>         * ld.texi: Document -plugin-save-temps.
>         * ldlex.h (option_values): Add OPTION_PLUGIN_SAVE_TEMPS.
>         * lexsup.c (ld_options): Add -plugin-save-temps.
>         (parse_args): Handle OPTION_PLUGIN_SAVE_TEMPS.
>         * plugin.c (plugin_call_cleanup): Don't call plugin
>         cleanup_handler for -plugin-save-temps.
> ---
>  ld/NEWS     |  2 ++
>  ld/ld.h     |  3 +++
>  ld/ld.texi  |  4 ++++
>  ld/ldlex.h  |  1 +
>  ld/lexsup.c |  6 ++++++
>  ld/plugin.c | 19 +++++++++++--------
>  6 files changed, 27 insertions(+), 8 deletions(-)
>
> diff --git a/ld/NEWS b/ld/NEWS
> index f89ed8cae4a..8e3b3f1677c 100644
> --- a/ld/NEWS
> +++ b/ld/NEWS
> @@ -4,6 +4,8 @@
>    linker scripts in ELF and PE COFF linker to specify the input text
>    section order.
>
> +* Add -plugin-save-temps to store plugin intermediate files permanently.
> +
>  Changes in 2.42:
>
>  * Add -z mark-plt/-z nomark-plt options to x86-64 ELF linker to mark PLT
> diff --git a/ld/ld.h b/ld/ld.h
> index a80255a73ba..6e0e773e418 100644
> --- a/ld/ld.h
> +++ b/ld/ld.h
> @@ -300,6 +300,9 @@ typedef struct
>    /* The size of the hash table to use.  */
>    unsigned long hash_table_size;
>
> +  /* If set, store plugin intermediate files permanently.  */
> +  bool plugin_save_temps;
> +
>    /* If set, print discarded sections in map file output.  */
>    bool print_map_discarded;
>
> diff --git a/ld/ld.texi b/ld/ld.texi
> index 2e715470ab6..4510905eee7 100644
> --- a/ld/ld.texi
> +++ b/ld/ld.texi
> @@ -1140,6 +1140,10 @@ Omit debugger symbol information (but not all symbols) from the output file.
>  Omit (or do not omit) global symbols defined in discarded sections.
>  Enabled by default.
>
> +@kindex -plugin-save-temps
> +@item -plugin-save-temps
> +Store the plugin ``temporary'' intermediate files permanently.
> +
>  @kindex -t
>  @kindex --trace
>  @cindex input files, displaying
> diff --git a/ld/ldlex.h b/ld/ldlex.h
> index a2c49656e1a..dd9e1b7e653 100644
> --- a/ld/ldlex.h
> +++ b/ld/ldlex.h
> @@ -147,6 +147,7 @@ enum option_values
>  #if BFD_SUPPORTS_PLUGINS
>    OPTION_PLUGIN,
>    OPTION_PLUGIN_OPT,
> +  OPTION_PLUGIN_SAVE_TEMPS,
>  #endif /* BFD_SUPPORTS_PLUGINS */
>    OPTION_DEFAULT_SCRIPT,
>    OPTION_PRINT_OUTPUT_FORMAT,
> diff --git a/ld/lexsup.c b/ld/lexsup.c
> index 21385628020..d043bdc37ae 100644
> --- a/ld/lexsup.c
> +++ b/ld/lexsup.c
> @@ -187,6 +187,9 @@ static const struct ld_option ld_options[] =
>      '\0', N_("PLUGIN"), N_("Load named plugin"), ONE_DASH },
>    { {"plugin-opt", required_argument, NULL, OPTION_PLUGIN_OPT},
>      '\0', N_("ARG"), N_("Send arg to last-loaded plugin"), ONE_DASH },
> +  { {"plugin-save-temps", no_argument, NULL, OPTION_PLUGIN_SAVE_TEMPS},
> +    '\0', NULL, N_("Store plugin intermediate files permanently"),
> +    ONE_DASH },
>    { {"flto", optional_argument, NULL, OPTION_IGNORE},
>      '\0', NULL, N_("Ignored for GCC LTO option compatibility"),
>      ONE_DASH },
> @@ -1215,6 +1218,9 @@ parse_args (unsigned argc, char **argv)
>           if (plugin_opt_plugin_arg (optarg))
>             einfo (_("%F%P: bad -plugin-opt option\n"));
>           break;
> +       case OPTION_PLUGIN_SAVE_TEMPS:
> +         config.plugin_save_temps = true;
> +         break;
>  #endif /* BFD_SUPPORTS_PLUGINS */
>         case 'q':
>           link_info.emitrelocations = true;
> diff --git a/ld/plugin.c b/ld/plugin.c
> index e982869072b..0d90dbc96e9 100644
> --- a/ld/plugin.c
> +++ b/ld/plugin.c
> @@ -1363,14 +1363,17 @@ plugin_call_cleanup (void)
>      {
>        if (curplug->cleanup_handler && !curplug->cleanup_done)
>         {
> -         enum ld_plugin_status rv;
> -         curplug->cleanup_done = true;
> -         called_plugin = curplug;
> -         rv = (*curplug->cleanup_handler) ();
> -         called_plugin = NULL;
> -         if (rv != LDPS_OK)
> -           info_msg (_("%P: %s: error in plugin cleanup: %d (ignored)\n"),
> -                     curplug->name, rv);
> +         if (!config.plugin_save_temps)
> +           {
> +             enum ld_plugin_status rv;
> +             curplug->cleanup_done = true;
> +             called_plugin = curplug;
> +             rv = (*curplug->cleanup_handler) ();
> +             called_plugin = NULL;
> +             if (rv != LDPS_OK)
> +               info_msg (_("%P: %s: error in plugin cleanup: %d (ignored)\n"),
> +                         curplug->name, rv);
> +           }
>           dlclose (curplug->dlhandle);
>         }
>        curplug = curplug->next;
> --
> 2.43.0
>

This simple change can be very useful.   Any comments and feedback?

Thanks.
  
Alan Modra Feb. 16, 2024, 12:42 p.m. UTC | #2
On Fri, Feb 16, 2024 at 04:17:23AM -0800, H.J. Lu wrote:
> On Sat, Feb 10, 2024 at 5:42 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > Add -plugin-save-temps to store plugin intermediate files permanently.
> > It can be used to exam the final input object files generated from IR
> > inputs.
> >
> >         * NEWS: Mention -plugin-save-temps.
> >         * ld.h (ld_config_type): Add plugin_save_temps.
> >         * ld.texi: Document -plugin-save-temps.
> >         * ldlex.h (option_values): Add OPTION_PLUGIN_SAVE_TEMPS.
> >         * lexsup.c (ld_options): Add -plugin-save-temps.
> >         (parse_args): Handle OPTION_PLUGIN_SAVE_TEMPS.
> >         * plugin.c (plugin_call_cleanup): Don't call plugin
> >         cleanup_handler for -plugin-save-temps.
> > ---
> >  ld/NEWS     |  2 ++
> >  ld/ld.h     |  3 +++
> >  ld/ld.texi  |  4 ++++
> >  ld/ldlex.h  |  1 +
> >  ld/lexsup.c |  6 ++++++
> >  ld/plugin.c | 19 +++++++++++--------
> >  6 files changed, 27 insertions(+), 8 deletions(-)
> >
> > diff --git a/ld/NEWS b/ld/NEWS
> > index f89ed8cae4a..8e3b3f1677c 100644
> > --- a/ld/NEWS
> > +++ b/ld/NEWS
> > @@ -4,6 +4,8 @@
> >    linker scripts in ELF and PE COFF linker to specify the input text
> >    section order.
> >
> > +* Add -plugin-save-temps to store plugin intermediate files permanently.
> > +
> >  Changes in 2.42:
> >
> >  * Add -z mark-plt/-z nomark-plt options to x86-64 ELF linker to mark PLT
> > diff --git a/ld/ld.h b/ld/ld.h
> > index a80255a73ba..6e0e773e418 100644
> > --- a/ld/ld.h
> > +++ b/ld/ld.h
> > @@ -300,6 +300,9 @@ typedef struct
> >    /* The size of the hash table to use.  */
> >    unsigned long hash_table_size;
> >
> > +  /* If set, store plugin intermediate files permanently.  */
> > +  bool plugin_save_temps;
> > +
> >    /* If set, print discarded sections in map file output.  */
> >    bool print_map_discarded;
> >
> > diff --git a/ld/ld.texi b/ld/ld.texi
> > index 2e715470ab6..4510905eee7 100644
> > --- a/ld/ld.texi
> > +++ b/ld/ld.texi
> > @@ -1140,6 +1140,10 @@ Omit debugger symbol information (but not all symbols) from the output file.
> >  Omit (or do not omit) global symbols defined in discarded sections.
> >  Enabled by default.
> >
> > +@kindex -plugin-save-temps
> > +@item -plugin-save-temps
> > +Store the plugin ``temporary'' intermediate files permanently.
> > +
> >  @kindex -t
> >  @kindex --trace
> >  @cindex input files, displaying
> > diff --git a/ld/ldlex.h b/ld/ldlex.h
> > index a2c49656e1a..dd9e1b7e653 100644
> > --- a/ld/ldlex.h
> > +++ b/ld/ldlex.h
> > @@ -147,6 +147,7 @@ enum option_values
> >  #if BFD_SUPPORTS_PLUGINS
> >    OPTION_PLUGIN,
> >    OPTION_PLUGIN_OPT,
> > +  OPTION_PLUGIN_SAVE_TEMPS,
> >  #endif /* BFD_SUPPORTS_PLUGINS */
> >    OPTION_DEFAULT_SCRIPT,
> >    OPTION_PRINT_OUTPUT_FORMAT,
> > diff --git a/ld/lexsup.c b/ld/lexsup.c
> > index 21385628020..d043bdc37ae 100644
> > --- a/ld/lexsup.c
> > +++ b/ld/lexsup.c
> > @@ -187,6 +187,9 @@ static const struct ld_option ld_options[] =
> >      '\0', N_("PLUGIN"), N_("Load named plugin"), ONE_DASH },
> >    { {"plugin-opt", required_argument, NULL, OPTION_PLUGIN_OPT},
> >      '\0', N_("ARG"), N_("Send arg to last-loaded plugin"), ONE_DASH },
> > +  { {"plugin-save-temps", no_argument, NULL, OPTION_PLUGIN_SAVE_TEMPS},
> > +    '\0', NULL, N_("Store plugin intermediate files permanently"),
> > +    ONE_DASH },
> >    { {"flto", optional_argument, NULL, OPTION_IGNORE},
> >      '\0', NULL, N_("Ignored for GCC LTO option compatibility"),
> >      ONE_DASH },
> > @@ -1215,6 +1218,9 @@ parse_args (unsigned argc, char **argv)
> >           if (plugin_opt_plugin_arg (optarg))
> >             einfo (_("%F%P: bad -plugin-opt option\n"));
> >           break;
> > +       case OPTION_PLUGIN_SAVE_TEMPS:
> > +         config.plugin_save_temps = true;
> > +         break;
> >  #endif /* BFD_SUPPORTS_PLUGINS */
> >         case 'q':
> >           link_info.emitrelocations = true;
> > diff --git a/ld/plugin.c b/ld/plugin.c
> > index e982869072b..0d90dbc96e9 100644
> > --- a/ld/plugin.c
> > +++ b/ld/plugin.c
> > @@ -1363,14 +1363,17 @@ plugin_call_cleanup (void)
> >      {
> >        if (curplug->cleanup_handler && !curplug->cleanup_done)
> >         {
> > -         enum ld_plugin_status rv;
> > -         curplug->cleanup_done = true;
> > -         called_plugin = curplug;
> > -         rv = (*curplug->cleanup_handler) ();
> > -         called_plugin = NULL;
> > -         if (rv != LDPS_OK)
> > -           info_msg (_("%P: %s: error in plugin cleanup: %d (ignored)\n"),
> > -                     curplug->name, rv);
> > +         if (!config.plugin_save_temps)
> > +           {
> > +             enum ld_plugin_status rv;
> > +             curplug->cleanup_done = true;
> > +             called_plugin = curplug;
> > +             rv = (*curplug->cleanup_handler) ();
> > +             called_plugin = NULL;
> > +             if (rv != LDPS_OK)
> > +               info_msg (_("%P: %s: error in plugin cleanup: %d (ignored)\n"),
> > +                         curplug->name, rv);
> > +           }
> >           dlclose (curplug->dlhandle);
> >         }
> >        curplug = curplug->next;
> > --
> > 2.43.0
> >
> 
> This simple change can be very useful.   Any comments and feedback?

It certainly beats running the linker under gdb and putting a
breakpoint at the appropriate place.  I like it.
  
H.J. Lu Feb. 16, 2024, 12:59 p.m. UTC | #3
On Fri, Feb 16, 2024 at 4:42 AM Alan Modra <amodra@gmail.com> wrote:
>
> On Fri, Feb 16, 2024 at 04:17:23AM -0800, H.J. Lu wrote:
> > On Sat, Feb 10, 2024 at 5:42 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> > >
> > > Add -plugin-save-temps to store plugin intermediate files permanently.
> > > It can be used to exam the final input object files generated from IR
> > > inputs.
> > >
> > >         * NEWS: Mention -plugin-save-temps.
> > >         * ld.h (ld_config_type): Add plugin_save_temps.
> > >         * ld.texi: Document -plugin-save-temps.
> > >         * ldlex.h (option_values): Add OPTION_PLUGIN_SAVE_TEMPS.
> > >         * lexsup.c (ld_options): Add -plugin-save-temps.
> > >         (parse_args): Handle OPTION_PLUGIN_SAVE_TEMPS.
> > >         * plugin.c (plugin_call_cleanup): Don't call plugin
> > >         cleanup_handler for -plugin-save-temps.
> > > ---
> > >  ld/NEWS     |  2 ++
> > >  ld/ld.h     |  3 +++
> > >  ld/ld.texi  |  4 ++++
> > >  ld/ldlex.h  |  1 +
> > >  ld/lexsup.c |  6 ++++++
> > >  ld/plugin.c | 19 +++++++++++--------
> > >  6 files changed, 27 insertions(+), 8 deletions(-)
> > >
> > > diff --git a/ld/NEWS b/ld/NEWS
> > > index f89ed8cae4a..8e3b3f1677c 100644
> > > --- a/ld/NEWS
> > > +++ b/ld/NEWS
> > > @@ -4,6 +4,8 @@
> > >    linker scripts in ELF and PE COFF linker to specify the input text
> > >    section order.
> > >
> > > +* Add -plugin-save-temps to store plugin intermediate files permanently.
> > > +
> > >  Changes in 2.42:
> > >
> > >  * Add -z mark-plt/-z nomark-plt options to x86-64 ELF linker to mark PLT
> > > diff --git a/ld/ld.h b/ld/ld.h
> > > index a80255a73ba..6e0e773e418 100644
> > > --- a/ld/ld.h
> > > +++ b/ld/ld.h
> > > @@ -300,6 +300,9 @@ typedef struct
> > >    /* The size of the hash table to use.  */
> > >    unsigned long hash_table_size;
> > >
> > > +  /* If set, store plugin intermediate files permanently.  */
> > > +  bool plugin_save_temps;
> > > +
> > >    /* If set, print discarded sections in map file output.  */
> > >    bool print_map_discarded;
> > >
> > > diff --git a/ld/ld.texi b/ld/ld.texi
> > > index 2e715470ab6..4510905eee7 100644
> > > --- a/ld/ld.texi
> > > +++ b/ld/ld.texi
> > > @@ -1140,6 +1140,10 @@ Omit debugger symbol information (but not all symbols) from the output file.
> > >  Omit (or do not omit) global symbols defined in discarded sections.
> > >  Enabled by default.
> > >
> > > +@kindex -plugin-save-temps
> > > +@item -plugin-save-temps
> > > +Store the plugin ``temporary'' intermediate files permanently.
> > > +
> > >  @kindex -t
> > >  @kindex --trace
> > >  @cindex input files, displaying
> > > diff --git a/ld/ldlex.h b/ld/ldlex.h
> > > index a2c49656e1a..dd9e1b7e653 100644
> > > --- a/ld/ldlex.h
> > > +++ b/ld/ldlex.h
> > > @@ -147,6 +147,7 @@ enum option_values
> > >  #if BFD_SUPPORTS_PLUGINS
> > >    OPTION_PLUGIN,
> > >    OPTION_PLUGIN_OPT,
> > > +  OPTION_PLUGIN_SAVE_TEMPS,
> > >  #endif /* BFD_SUPPORTS_PLUGINS */
> > >    OPTION_DEFAULT_SCRIPT,
> > >    OPTION_PRINT_OUTPUT_FORMAT,
> > > diff --git a/ld/lexsup.c b/ld/lexsup.c
> > > index 21385628020..d043bdc37ae 100644
> > > --- a/ld/lexsup.c
> > > +++ b/ld/lexsup.c
> > > @@ -187,6 +187,9 @@ static const struct ld_option ld_options[] =
> > >      '\0', N_("PLUGIN"), N_("Load named plugin"), ONE_DASH },
> > >    { {"plugin-opt", required_argument, NULL, OPTION_PLUGIN_OPT},
> > >      '\0', N_("ARG"), N_("Send arg to last-loaded plugin"), ONE_DASH },
> > > +  { {"plugin-save-temps", no_argument, NULL, OPTION_PLUGIN_SAVE_TEMPS},
> > > +    '\0', NULL, N_("Store plugin intermediate files permanently"),
> > > +    ONE_DASH },
> > >    { {"flto", optional_argument, NULL, OPTION_IGNORE},
> > >      '\0', NULL, N_("Ignored for GCC LTO option compatibility"),
> > >      ONE_DASH },
> > > @@ -1215,6 +1218,9 @@ parse_args (unsigned argc, char **argv)
> > >           if (plugin_opt_plugin_arg (optarg))
> > >             einfo (_("%F%P: bad -plugin-opt option\n"));
> > >           break;
> > > +       case OPTION_PLUGIN_SAVE_TEMPS:
> > > +         config.plugin_save_temps = true;
> > > +         break;
> > >  #endif /* BFD_SUPPORTS_PLUGINS */
> > >         case 'q':
> > >           link_info.emitrelocations = true;
> > > diff --git a/ld/plugin.c b/ld/plugin.c
> > > index e982869072b..0d90dbc96e9 100644
> > > --- a/ld/plugin.c
> > > +++ b/ld/plugin.c
> > > @@ -1363,14 +1363,17 @@ plugin_call_cleanup (void)
> > >      {
> > >        if (curplug->cleanup_handler && !curplug->cleanup_done)
> > >         {
> > > -         enum ld_plugin_status rv;
> > > -         curplug->cleanup_done = true;
> > > -         called_plugin = curplug;
> > > -         rv = (*curplug->cleanup_handler) ();
> > > -         called_plugin = NULL;
> > > -         if (rv != LDPS_OK)
> > > -           info_msg (_("%P: %s: error in plugin cleanup: %d (ignored)\n"),
> > > -                     curplug->name, rv);
> > > +         if (!config.plugin_save_temps)
> > > +           {
> > > +             enum ld_plugin_status rv;
> > > +             curplug->cleanup_done = true;
> > > +             called_plugin = curplug;
> > > +             rv = (*curplug->cleanup_handler) ();
> > > +             called_plugin = NULL;
> > > +             if (rv != LDPS_OK)
> > > +               info_msg (_("%P: %s: error in plugin cleanup: %d (ignored)\n"),
> > > +                         curplug->name, rv);
> > > +           }
> > >           dlclose (curplug->dlhandle);
> > >         }
> > >        curplug = curplug->next;
> > > --
> > > 2.43.0
> > >
> >
> > This simple change can be very useful.   Any comments and feedback?
>
> It certainly beats running the linker under gdb and putting a
> breakpoint at the appropriate place.  I like it.
>
>

I am checking it in.

Thanks.
  

Patch

diff --git a/ld/NEWS b/ld/NEWS
index f89ed8cae4a..8e3b3f1677c 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -4,6 +4,8 @@ 
   linker scripts in ELF and PE COFF linker to specify the input text
   section order.
 
+* Add -plugin-save-temps to store plugin intermediate files permanently.
+
 Changes in 2.42:
 
 * Add -z mark-plt/-z nomark-plt options to x86-64 ELF linker to mark PLT
diff --git a/ld/ld.h b/ld/ld.h
index a80255a73ba..6e0e773e418 100644
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -300,6 +300,9 @@  typedef struct
   /* The size of the hash table to use.  */
   unsigned long hash_table_size;
 
+  /* If set, store plugin intermediate files permanently.  */
+  bool plugin_save_temps;
+
   /* If set, print discarded sections in map file output.  */
   bool print_map_discarded;
 
diff --git a/ld/ld.texi b/ld/ld.texi
index 2e715470ab6..4510905eee7 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1140,6 +1140,10 @@  Omit debugger symbol information (but not all symbols) from the output file.
 Omit (or do not omit) global symbols defined in discarded sections.
 Enabled by default.
 
+@kindex -plugin-save-temps
+@item -plugin-save-temps
+Store the plugin ``temporary'' intermediate files permanently.
+
 @kindex -t
 @kindex --trace
 @cindex input files, displaying
diff --git a/ld/ldlex.h b/ld/ldlex.h
index a2c49656e1a..dd9e1b7e653 100644
--- a/ld/ldlex.h
+++ b/ld/ldlex.h
@@ -147,6 +147,7 @@  enum option_values
 #if BFD_SUPPORTS_PLUGINS
   OPTION_PLUGIN,
   OPTION_PLUGIN_OPT,
+  OPTION_PLUGIN_SAVE_TEMPS,
 #endif /* BFD_SUPPORTS_PLUGINS */
   OPTION_DEFAULT_SCRIPT,
   OPTION_PRINT_OUTPUT_FORMAT,
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 21385628020..d043bdc37ae 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -187,6 +187,9 @@  static const struct ld_option ld_options[] =
     '\0', N_("PLUGIN"), N_("Load named plugin"), ONE_DASH },
   { {"plugin-opt", required_argument, NULL, OPTION_PLUGIN_OPT},
     '\0', N_("ARG"), N_("Send arg to last-loaded plugin"), ONE_DASH },
+  { {"plugin-save-temps", no_argument, NULL, OPTION_PLUGIN_SAVE_TEMPS},
+    '\0', NULL, N_("Store plugin intermediate files permanently"),
+    ONE_DASH },
   { {"flto", optional_argument, NULL, OPTION_IGNORE},
     '\0', NULL, N_("Ignored for GCC LTO option compatibility"),
     ONE_DASH },
@@ -1215,6 +1218,9 @@  parse_args (unsigned argc, char **argv)
 	  if (plugin_opt_plugin_arg (optarg))
 	    einfo (_("%F%P: bad -plugin-opt option\n"));
 	  break;
+	case OPTION_PLUGIN_SAVE_TEMPS:
+	  config.plugin_save_temps = true;
+	  break;
 #endif /* BFD_SUPPORTS_PLUGINS */
 	case 'q':
 	  link_info.emitrelocations = true;
diff --git a/ld/plugin.c b/ld/plugin.c
index e982869072b..0d90dbc96e9 100644
--- a/ld/plugin.c
+++ b/ld/plugin.c
@@ -1363,14 +1363,17 @@  plugin_call_cleanup (void)
     {
       if (curplug->cleanup_handler && !curplug->cleanup_done)
 	{
-	  enum ld_plugin_status rv;
-	  curplug->cleanup_done = true;
-	  called_plugin = curplug;
-	  rv = (*curplug->cleanup_handler) ();
-	  called_plugin = NULL;
-	  if (rv != LDPS_OK)
-	    info_msg (_("%P: %s: error in plugin cleanup: %d (ignored)\n"),
-		      curplug->name, rv);
+	  if (!config.plugin_save_temps)
+	    {
+	      enum ld_plugin_status rv;
+	      curplug->cleanup_done = true;
+	      called_plugin = curplug;
+	      rv = (*curplug->cleanup_handler) ();
+	      called_plugin = NULL;
+	      if (rv != LDPS_OK)
+		info_msg (_("%P: %s: error in plugin cleanup: %d (ignored)\n"),
+			  curplug->name, rv);
+	    }
 	  dlclose (curplug->dlhandle);
 	}
       curplug = curplug->next;