OSDN Git Service

PR driver/42690
[pf3gnuchains/gcc-fork.git] / gcc / gcc.c
index 13635d5..c2998bd 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -47,6 +47,7 @@ compilation is specified by a string called a "spec".  */
 #include "diagnostic.h"
 #include "flags.h"
 #include "opts.h"
+#include "vec.h"
 
 #ifdef HAVE_MMAP_FILE
 # include <sys/mman.h>
@@ -114,10 +115,6 @@ static int print_help_list;
 
 static int print_version;
 
-/* Flag indicating whether we should print the command and arguments */
-
-static int verbose_flag;
-
 /* Flag indicating whether we should ONLY print the command and
    arguments (like verbose_flag) without executing the command.
    Displayed arguments are quoted so that the generated command
@@ -287,6 +284,7 @@ static const char *print_asm_header_spec_function (int, const char **);
 static const char *compare_debug_dump_opt_spec_function (int, const char **);
 static const char *compare_debug_self_opt_spec_function (int, const char **);
 static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
+static const char *pass_through_libs_spec_func (int, const char **);
 \f
 /* The Specs Language
 
@@ -649,7 +647,7 @@ proper position among the other output files.  */
 /* We want %{T*} after %{L*} and %D so that it can be used to specify linker
    scripts which exist in user specified directories, or in standard
    directories.  */
-/* We pass any -flto and -fwhopr flags on to the linker, which is expected
+/* We pass any -flto flags on to the linker, which is expected
    to understand them.  In practice, this means it had better be collect2.  */
 #ifndef LINK_COMMAND_SPEC
 #define LINK_COMMAND_SPEC "\
@@ -659,13 +657,12 @@ proper position among the other output files.  */
     -plugin %(linker_plugin_file) \
     -plugin-opt=%(lto_wrapper) \
     -plugin-opt=-fresolution=%u.res \
-    %{static|static-libgcc:-plugin-opt=-pass-through=%(lto_libgcc)}    \
-    %{static:-plugin-opt=-pass-through=-lc}    \
+    %{!nostdlib:%{!nodefaultlibs:%:pass-through-libs(%(link_gcc_c_sequence))}} \
     } \
-    %{flto:%<fcompare-debug*} %{fwhopr*:%<fcompare-debug*} \
-    %{flto} %{fwhopr*} %l " LINK_PIE_SPEC \
+    %{flto*:%<fcompare-debug*} \
+    %{flto*} %l " LINK_PIE_SPEC \
    "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
-    %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
+    %{s} %{t} %{u*} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
     %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\
     %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\
     %(mflib) " STACK_SPLIT_SPEC "\
@@ -715,7 +712,6 @@ static const char *linker_name_spec = LINKER_NAME;
 static const char *linker_plugin_file_spec = "";
 static const char *lto_wrapper_spec = "";
 static const char *lto_gcc_spec = "";
-static const char *lto_libgcc_spec = "";
 static const char *link_command_spec = LINK_COMMAND_SPEC;
 static const char *link_libgcc_spec = LINK_LIBGCC_SPEC;
 static const char *startfile_prefix_spec = STARTFILE_PREFIX_SPEC;
@@ -986,23 +982,24 @@ static const struct compiler default_compilers[] =
 
 static const int n_default_compilers = ARRAY_SIZE (default_compilers) - 1;
 
+typedef char *char_p; /* For DEF_VEC_P.  */
+DEF_VEC_P(char_p);
+DEF_VEC_ALLOC_P(char_p,heap);
+
 /* A vector of options to give to the linker.
    These options are accumulated by %x,
    and substituted into the linker command with %X.  */
-static int n_linker_options;
-static char **linker_options;
+static VEC(char_p,heap) *linker_options;
 
 /* A vector of options to give to the assembler.
    These options are accumulated by -Wa,
    and substituted into the assembler command with %Y.  */
-static int n_assembler_options;
-static char **assembler_options;
+static VEC(char_p,heap) *assembler_options;
 
 /* A vector of options to give to the preprocessor.
    These options are accumulated by -Wp,
    and substituted into the preprocessor command with %Z.  */
-static int n_preprocessor_options;
-static char **preprocessor_options;
+static VEC(char_p,heap) *preprocessor_options;
 \f
 static char *
 skip_whitespace (char *p)
@@ -1199,7 +1196,6 @@ static struct spec_list static_specs[] =
   INIT_STATIC_SPEC ("linker_plugin_file",      &linker_plugin_file_spec),
   INIT_STATIC_SPEC ("lto_wrapper",             &lto_wrapper_spec),
   INIT_STATIC_SPEC ("lto_gcc",                 &lto_gcc_spec),
-  INIT_STATIC_SPEC ("lto_libgcc",              &lto_libgcc_spec),
   INIT_STATIC_SPEC ("link_libgcc",             &link_libgcc_spec),
   INIT_STATIC_SPEC ("md_exec_prefix",          &md_exec_prefix),
   INIT_STATIC_SPEC ("md_startfile_prefix",     &md_startfile_prefix),
@@ -1244,6 +1240,7 @@ static const struct spec_function static_spec_functions[] =
   { "compare-debug-dump-opt",  compare_debug_dump_opt_spec_function },
   { "compare-debug-self-opt",  compare_debug_self_opt_spec_function },
   { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
+  { "pass-through-libs",       pass_through_libs_spec_func },
 #ifdef EXTRA_SPEC_FUNCTIONS
   EXTRA_SPEC_FUNCTIONS
 #endif
@@ -1507,19 +1504,15 @@ set_spec (const char *name, const char *spec)
 \f
 /* Accumulate a command (program name and args), and run it.  */
 
-/* Vector of pointers to arguments in the current line of specifications.  */
-
-static const char **argbuf;
-
-/* Number of elements allocated in argbuf.  */
-
-static int argbuf_length;
+typedef const char *const_char_p; /* For DEF_VEC_P.  */
+DEF_VEC_P(const_char_p);
+DEF_VEC_ALLOC_P(const_char_p,heap);
 
-/* Number of elements in argbuf currently in use (containing args).  */
+/* Vector of pointers to arguments in the current line of specifications.  */
 
-static int argbuf_index;
+static VEC(const_char_p,heap) *argbuf;
 
-/* Position in the argbuf array containing the name of the output file
+/* Position in the argbuf vector containing the name of the output file
    (the value associated with the "-o" flag).  */
 
 static int have_o_argbuf_index = 0;
@@ -1556,8 +1549,7 @@ static int signal_count;
 static void
 alloc_args (void)
 {
-  argbuf_length = 10;
-  argbuf = XNEWVEC (const char *, argbuf_length);
+  argbuf = VEC_alloc (const_char_p, heap, 10);
 }
 
 /* Clear out the vector of arguments (after a command is executed).  */
@@ -1565,7 +1557,7 @@ alloc_args (void)
 static void
 clear_args (void)
 {
-  argbuf_index = 0;
+  VEC_truncate (const_char_p, argbuf, 0);
 }
 
 /* Add one argument to the vector at the end.
@@ -1578,14 +1570,10 @@ clear_args (void)
 static void
 store_arg (const char *arg, int delete_always, int delete_failure)
 {
-  if (argbuf_index + 1 == argbuf_length)
-    argbuf = XRESIZEVEC (const char *, argbuf, (argbuf_length *= 2));
-
-  argbuf[argbuf_index++] = arg;
-  argbuf[argbuf_index] = 0;
+  VEC_safe_push (const_char_p, heap, argbuf, arg);
 
   if (strcmp (arg, "-o") == 0)
-    have_o_argbuf_index = argbuf_index;
+    have_o_argbuf_index = VEC_length (const_char_p, argbuf);
   if (delete_always || delete_failure)
     {
       const char *p;
@@ -2463,6 +2451,7 @@ execute (void)
     const char *prog;          /* program name.  */
     const char **argv;         /* vector of args.  */
   };
+  const char *arg;
 
   struct command *commands;    /* each command buffer with above info.  */
 
@@ -2470,14 +2459,16 @@ execute (void)
 
   if (wrapper_string)
     {
-      string = find_a_file (&exec_prefixes, argbuf[0], X_OK, false);
-      argbuf[0] = (string) ? string : argbuf[0];
+      string = find_a_file (&exec_prefixes,
+                           VEC_index (const_char_p, argbuf, 0), X_OK, false);
+      if (string)
+       VEC_replace (const_char_p, argbuf, 0, string);
       insert_wrapper (wrapper_string);
     }
 
   /* Count # of piped commands.  */
-  for (n_commands = 1, i = 0; i < argbuf_index; i++)
-    if (strcmp (argbuf[i], "|") == 0)
+  for (n_commands = 1, i = 0; VEC_iterate (const_char_p, argbuf, i, arg); i++)
+    if (strcmp (arg, "|") == 0)
       n_commands++;
 
   /* Get storage for each command.  */
@@ -2487,8 +2478,10 @@ execute (void)
      and record info about each one.
      Also search for the programs that are to be run.  */
 
-  commands[0].prog = argbuf[0]; /* first command.  */
-  commands[0].argv = &argbuf[0];
+  VEC_safe_push (const_char_p, heap, argbuf, 0);
+
+  commands[0].prog = VEC_index (const_char_p, argbuf, 0); /* first command.  */
+  commands[0].argv = VEC_address (const_char_p, argbuf);
 
   if (!wrapper_string)
     {
@@ -2496,15 +2489,17 @@ execute (void)
       commands[0].argv[0] = (string) ? string : commands[0].argv[0];
     }
 
-  for (n_commands = 1, i = 0; i < argbuf_index; i++)
-    if (strcmp (argbuf[i], "|") == 0)
+  for (n_commands = 1, i = 0; VEC_iterate (const_char_p, argbuf, i, arg); i++)
+    if (arg && strcmp (arg, "|") == 0)
       {                                /* each command.  */
 #if defined (__MSDOS__) || defined (OS2) || defined (VMS)
        fatal_error ("-pipe not supported");
 #endif
-       argbuf[i] = 0;  /* termination of command args.  */
-       commands[n_commands].prog = argbuf[i + 1];
-       commands[n_commands].argv = &argbuf[i + 1];
+       VEC_replace (const_char_p, argbuf, i, 0); /* Termination of
+                                                    command args.  */
+       commands[n_commands].prog = VEC_index (const_char_p, argbuf, i + 1);
+       commands[n_commands].argv
+         = &(VEC_address (const_char_p, argbuf))[i + 1];
        string = find_a_file (&exec_prefixes, commands[n_commands].prog,
                              X_OK, false);
        if (string)
@@ -2512,8 +2507,6 @@ execute (void)
        n_commands++;
       }
 
-  argbuf[argbuf_index] = 0;
-
   /* If -v, print what we are about to do, and maybe query.  */
 
   if (verbose_flag)
@@ -2982,43 +2975,20 @@ display_help (void)
 static void
 add_preprocessor_option (const char *option, int len)
 {
-  n_preprocessor_options++;
-
-  if (! preprocessor_options)
-    preprocessor_options = XNEWVEC (char *, n_preprocessor_options);
-  else
-    preprocessor_options = XRESIZEVEC (char *, preprocessor_options,
-                                      n_preprocessor_options);
-
-  preprocessor_options [n_preprocessor_options - 1] =
-    save_string (option, len);
+  VEC_safe_push (char_p, heap, preprocessor_options,
+                save_string (option, len));
 }
 
 static void
 add_assembler_option (const char *option, int len)
 {
-  n_assembler_options++;
-
-  if (! assembler_options)
-    assembler_options = XNEWVEC (char *, n_assembler_options);
-  else
-    assembler_options = XRESIZEVEC (char *, assembler_options,
-                                   n_assembler_options);
-
-  assembler_options [n_assembler_options - 1] = save_string (option, len);
+  VEC_safe_push (char_p, heap, assembler_options, save_string (option, len));
 }
 
 static void
 add_linker_option (const char *option, int len)
 {
-  n_linker_options++;
-
-  if (! linker_options)
-    linker_options = XNEWVEC (char *, n_linker_options);
-  else
-    linker_options = XRESIZEVEC (char *, linker_options, n_linker_options);
-
-  linker_options [n_linker_options - 1] = save_string (option, len);
+  VEC_safe_push (char_p, heap, linker_options, save_string (option, len));
 }
 \f
 /* Allocate space for an input file in infiles.  */
@@ -3145,7 +3115,9 @@ driver_handle_option (struct gcc_options *opts,
                      struct gcc_options *opts_set,
                      const struct cl_decoded_option *decoded,
                      unsigned int lang_mask ATTRIBUTE_UNUSED, int kind,
-                     const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
+                     location_t loc,
+                     const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED,
+                     diagnostic_context *dc)
 {
   size_t opt_index = decoded->opt_index;
   const char *arg = decoded->arg;
@@ -3157,6 +3129,8 @@ driver_handle_option (struct gcc_options *opts,
   gcc_assert (opts == &global_options);
   gcc_assert (opts_set == &global_options_set);
   gcc_assert (kind == DK_UNSPECIFIED);
+  gcc_assert (loc == UNKNOWN_LOCATION);
+  gcc_assert (dc == global_dc);
 
   switch (opt_index)
     {
@@ -3421,7 +3395,7 @@ driver_handle_option (struct gcc_options *opts,
         is intended for use in shell scripts to capture the
         driver-generated command line.  */
       verbose_only_flag++;
-      verbose_flag++;
+      verbose_flag = 1;
       do_save = false;
       break;
 
@@ -3456,10 +3430,6 @@ driver_handle_option (struct gcc_options *opts,
       validated = true;
       break;
 
-    case OPT_v:        /* Print our subcommands and print versions.  */
-      verbose_flag++;
-      break;
-
     case OPT_x:
       spec_lang = arg;
       if (!strcmp (spec_lang, "none"))
@@ -3805,8 +3775,8 @@ process_command (unsigned int decoded_options_count,
        }
 
       read_cmdline_option (&global_options, &global_options_set,
-                          decoded_options + j, CL_DRIVER, &handlers,
-                          global_dc);
+                          decoded_options + j, UNKNOWN_LOCATION,
+                          CL_DRIVER, &handlers, global_dc);
     }
 
   /* If -save-temps=obj and -o name, create the prefix to use for %b.
@@ -4108,6 +4078,7 @@ insert_wrapper (const char *wrapper)
   int i;
   char *buf = xstrdup (wrapper);
   char *p = buf;
+  unsigned int old_length = VEC_length (const_char_p, argbuf);
 
   do
     {
@@ -4117,15 +4088,10 @@ insert_wrapper (const char *wrapper)
     }
   while ((p = strchr (p, ',')) != NULL);
 
-  if (argbuf_index + n >= argbuf_length)
-    {
-      argbuf_length = argbuf_length * 2;
-      while (argbuf_length < argbuf_index + n)
-       argbuf_length *= 2;
-      argbuf = XRESIZEVEC (const char *, argbuf, argbuf_length);
-    }
-  for (i = argbuf_index - 1; i >= 0; i--)
-    argbuf[i + n] = argbuf[i];
+  VEC_safe_grow (const_char_p, heap, argbuf, old_length + n);
+  memmove (VEC_address (const_char_p, argbuf) + n,
+          VEC_address (const_char_p, argbuf),
+          old_length * sizeof (const_char_p));
 
   i = 0;
   p = buf;
@@ -4136,11 +4102,11 @@ insert_wrapper (const char *wrapper)
           *p = 0;
           p++;
         }
-      argbuf[i++] = p;
+      VEC_replace (const_char_p, argbuf, i, p);
+      i++;
     }
   while ((p = strchr (p, ',')) != NULL);
   gcc_assert (i == n);
-  argbuf_index += n;
 }
 
 /* Process the spec SPEC and run the commands specified therein.
@@ -4157,12 +4123,13 @@ do_spec (const char *spec)
      If -pipe, this forces out the last command if it ended in `|'.  */
   if (value == 0)
     {
-      if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|"))
-       argbuf_index--;
+      if (VEC_length (const_char_p, argbuf) > 0
+         && !strcmp (VEC_last (const_char_p, argbuf), "|"))
+       VEC_pop (const_char_p, argbuf);
 
       set_collect_gcc_options ();
 
-      if (argbuf_index > 0)
+      if (VEC_length (const_char_p, argbuf) > 0)
        value = execute ();
     }
 
@@ -4258,7 +4225,7 @@ do_self_spec (const char *spec)
     if ((switches[i].live_cond & SWITCH_IGNORE))
       switches[i].live_cond |= SWITCH_IGNORE_PERMANENTLY;
 
-  if (argbuf_index > 0)
+  if (VEC_length (const_char_p, argbuf) > 0)
     {
       const char **argbuf_copy;
       struct cl_decoded_option *decoded_options;
@@ -4268,11 +4235,14 @@ do_self_spec (const char *spec)
 
       /* Create a copy of argbuf with a dummy argv[0] entry for
         decode_cmdline_options_to_array.  */
-      argbuf_copy = XNEWVEC (const char *, argbuf_index + 1);
+      argbuf_copy = XNEWVEC (const char *,
+                            VEC_length (const_char_p, argbuf) + 1);
       argbuf_copy[0] = "";
-      memcpy (argbuf_copy + 1, argbuf, argbuf_index * sizeof (const char *));
+      memcpy (argbuf_copy + 1, VEC_address (const_char_p, argbuf),
+             VEC_length (const_char_p, argbuf) * sizeof (const char *));
 
-      decode_cmdline_options_to_array (argbuf_index + 1, argbuf_copy,
+      decode_cmdline_options_to_array (VEC_length (const_char_p, argbuf) + 1,
+                                      argbuf_copy,
                                       CL_DRIVER, &decoded_options,
                                       &decoded_options_count);
 
@@ -4306,8 +4276,8 @@ do_self_spec (const char *spec)
 
            default:
              read_cmdline_option (&global_options, &global_options_set,
-                                  decoded_options + j, CL_DRIVER, &handlers,
-                                  global_dc);
+                                  decoded_options + j, UNKNOWN_LOCATION,
+                                  CL_DRIVER, &handlers, global_dc);
              break;
            }
        }
@@ -4411,6 +4381,22 @@ compile_input_file_p (struct infile *infile)
   return false;
 }
 
+/* Process each member of VEC as a spec.  */
+
+static void
+do_specs_vec (VEC(char_p,heap) *vec)
+{
+  unsigned ix;
+  char *opt;
+
+  FOR_EACH_VEC_ELT (char_p, vec, ix, opt)
+    {
+      do_spec_1 (opt, 1, NULL);
+      /* Make each accumulated option a separate argument.  */
+      do_spec_1 (" ", 0, NULL);
+    }
+}
+
 /* Process the sub-spec SPEC as a portion of a larger spec.
    This is like processing a whole spec except that we do
    not initialize at the beginning and we do not supply a
@@ -4439,7 +4425,8 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
       case '\n':
        end_going_arg ();
 
-       if (argbuf_index > 0 && !strcmp (argbuf[argbuf_index - 1], "|"))
+       if (VEC_length (const_char_p, argbuf) > 0
+           && !strcmp (VEC_last (const_char_p, argbuf), "|"))
          {
            /* A `|' before the newline means use a pipe here,
               but only if -pipe was specified.
@@ -4450,12 +4437,12 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
                break;
              }
            else
-             argbuf_index--;
+             VEC_pop (const_char_p, argbuf);
          }
 
        set_collect_gcc_options ();
 
-       if (argbuf_index > 0)
+       if (VEC_length (const_char_p, argbuf) > 0)
          {
            value = execute ();
            if (value)
@@ -4951,7 +4938,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
 
          case 'W':
            {
-             int cur_index = argbuf_index;
+             unsigned int cur_index = VEC_length (const_char_p, argbuf);
              /* Handle the {...} following the %W.  */
              if (*p != '{')
                fatal_error ("spec %qs has invalid %<%%W%c%>", spec, *p);
@@ -4961,8 +4948,8 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
              end_going_arg ();
              /* If any args were output, mark the last one for deletion
                 on failure.  */
-             if (argbuf_index != cur_index)
-               record_temp_file (argbuf[argbuf_index - 1], 0, 1);
+             if (VEC_length (const_char_p, argbuf) != cur_index)
+               record_temp_file (VEC_last (const_char_p, argbuf), 0, 1);
              break;
            }
 
@@ -4971,6 +4958,8 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
            {
              const char *p1 = p;
              char *string;
+             char *opt;
+             unsigned ix;
 
              /* Skip past the option value and make a copy.  */
              if (*p != '{')
@@ -4980,8 +4969,8 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
              string = save_string (p1 + 1, p - p1 - 2);
 
              /* See if we already recorded this option.  */
-             for (i = 0; i < n_linker_options; i++)
-               if (! strcmp (string, linker_options[i]))
+             FOR_EACH_VEC_ELT (char_p, linker_options, ix, opt)
+               if (! strcmp (string, opt))
                  {
                    free (string);
                    return 0;
@@ -4994,32 +4983,17 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
 
          /* Dump out the options accumulated previously using %x.  */
          case 'X':
-           for (i = 0; i < n_linker_options; i++)
-             {
-               do_spec_1 (linker_options[i], 1, NULL);
-               /* Make each accumulated option a separate argument.  */
-               do_spec_1 (" ", 0, NULL);
-             }
+           do_specs_vec (linker_options);
            break;
 
          /* Dump out the options accumulated previously using -Wa,.  */
          case 'Y':
-           for (i = 0; i < n_assembler_options; i++)
-             {
-               do_spec_1 (assembler_options[i], 1, NULL);
-               /* Make each accumulated option a separate argument.  */
-               do_spec_1 (" ", 0, NULL);
-             }
+           do_specs_vec (assembler_options);
            break;
 
          /* Dump out the options accumulated previously using -Wp,.  */
          case 'Z':
-           for (i = 0; i < n_preprocessor_options; i++)
-             {
-               do_spec_1 (preprocessor_options[i], 1, NULL);
-               /* Make each accumulated option a separate argument.  */
-               do_spec_1 (" ", 0, NULL);
-             }
+           do_specs_vec (preprocessor_options);
            break;
 
            /* Here are digits and numbers that just process
@@ -5306,9 +5280,7 @@ eval_spec_function (const char *func, const char *args)
   const char *funcval;
 
   /* Saved spec processing context.  */
-  int save_argbuf_index;
-  int save_argbuf_length;
-  const char **save_argbuf;
+  VEC(const_char_p,heap) *save_argbuf;
 
   int save_arg_going;
   int save_delete_this_arg;
@@ -5324,8 +5296,6 @@ eval_spec_function (const char *func, const char *args)
     fatal_error ("unknown spec function %qs", func);
 
   /* Push the spec processing context.  */
-  save_argbuf_index = argbuf_index;
-  save_argbuf_length = argbuf_length;
   save_argbuf = argbuf;
 
   save_arg_going = arg_going;
@@ -5346,12 +5316,11 @@ eval_spec_function (const char *func, const char *args)
   /* argbuf_index is an index for the next argument to be inserted, and
      so contains the count of the args already inserted.  */
 
-  funcval = (*sf->func) (argbuf_index, argbuf);
+  funcval = (*sf->func) (VEC_length (const_char_p, argbuf),
+                        VEC_address (const_char_p, argbuf));
 
   /* Pop the spec processing context.  */
-  argbuf_index = save_argbuf_index;
-  argbuf_length = save_argbuf_length;
-  free (argbuf);
+  VEC_free (const_char_p, heap, argbuf);
   argbuf = save_argbuf;
 
   arg_going = save_arg_going;
@@ -6104,6 +6073,7 @@ main (int argc, char **argv)
   int num_linker_inputs = 0;
   char *explicit_link_files;
   char *specs_file;
+  char *lto_wrapper_file;
   const char *p;
   struct user_specs *uptr;
   char **old_argv = argv;
@@ -6324,10 +6294,10 @@ main (int argc, char **argv)
   if (*sysroot_suffix_spec != 0
       && do_spec_2 (sysroot_suffix_spec) == 0)
     {
-      if (argbuf_index > 1)
+      if (VEC_length (const_char_p, argbuf) > 1)
         error ("spec failure: more than one arg to SYSROOT_SUFFIX_SPEC");
-      else if (argbuf_index == 1)
-        target_sysroot_suffix = xstrdup (argbuf[argbuf_index -1]);
+      else if (VEC_length (const_char_p, argbuf) == 1)
+        target_sysroot_suffix = xstrdup (VEC_last (const_char_p, argbuf));
     }
 
 #ifdef HAVE_LD_SYSROOT
@@ -6347,10 +6317,10 @@ main (int argc, char **argv)
   if (*sysroot_hdrs_suffix_spec != 0
       && do_spec_2 (sysroot_hdrs_suffix_spec) == 0)
     {
-      if (argbuf_index > 1)
+      if (VEC_length (const_char_p, argbuf) > 1)
         error ("spec failure: more than one arg to SYSROOT_HEADERS_SUFFIX_SPEC");
-      else if (argbuf_index == 1)
-        target_sysroot_hdrs_suffix = xstrdup (argbuf[argbuf_index -1]);
+      else if (VEC_length (const_char_p, argbuf) == 1)
+        target_sysroot_hdrs_suffix = xstrdup (VEC_last (const_char_p, argbuf));
     }
 
   /* Look for startfiles in the standard places.  */
@@ -6358,9 +6328,10 @@ main (int argc, char **argv)
       && do_spec_2 (startfile_prefix_spec) == 0
       && do_spec_1 (" ", 0, NULL) == 0)
     {
+      const char *arg;
       int ndx;
-      for (ndx = 0; ndx < argbuf_index; ndx++)
-       add_sysrooted_prefix (&startfile_prefixes, argbuf[ndx], "BINUTILS",
+      FOR_EACH_VEC_ELT (const_char_p, argbuf, ndx, arg)
+       add_sysrooted_prefix (&startfile_prefixes, arg, "BINUTILS",
                              PREFIX_PRIORITY_LAST, 0, 1);
     }
   /* We should eventually get rid of all these and stick to
@@ -6441,9 +6412,10 @@ main (int argc, char **argv)
 
   /* Set up to remember the pathname of the lto wrapper. */
 
-  lto_wrapper_spec = find_a_file (&exec_prefixes, "lto-wrapper", X_OK, false);
-  if (lto_wrapper_spec)
+  lto_wrapper_file = find_a_file (&exec_prefixes, "lto-wrapper", X_OK, false);
+  if (lto_wrapper_file)
     {
+      lto_wrapper_spec = lto_wrapper_file;
       obstack_init (&collect_obstack);
       obstack_grow (&collect_obstack, "COLLECT_LTO_WRAPPER=",
                    sizeof ("COLLECT_LTO_WRAPPER=") - 1);
@@ -6832,11 +6804,6 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
                                                 false);
          if (!linker_plugin_file_spec)
            fatal_error ("-fuse-linker-plugin, but " LTOPLUGINSONAME " not found");
-
-         lto_libgcc_spec = find_a_file (&startfile_prefixes, "libgcc.a",
-                                        R_OK, true);
-         if (!lto_libgcc_spec)
-           fatal_error ("could not find libgcc.a");
        }
       lto_gcc_spec = argv[0];
 
@@ -8091,19 +8058,20 @@ compare_debug_dump_opt_spec_function (int arg,
   do_spec_2 ("%{fdump-final-insns=*:%*}");
   do_spec_1 (" ", 0, NULL);
 
-  if (argbuf_index > 0 && strcmp (argv[argbuf_index - 1], "."))
+  if (VEC_length (const_char_p, argbuf) > 0
+      && strcmp (argv[VEC_length (const_char_p, argbuf) - 1], "."))
     {
       if (!compare_debug)
        return NULL;
 
-      name = xstrdup (argv[argbuf_index - 1]);
+      name = xstrdup (argv[VEC_length (const_char_p, argbuf) - 1]);
       ret = NULL;
     }
   else
     {
       const char *ext = NULL;
 
-      if (argbuf_index > 0)
+      if (VEC_length (const_char_p, argbuf) > 0)
        {
          do_spec_2 ("%{o*:%*}%{!o:%{!S:%b%O}%{S:%b.s}}");
          ext = ".gkd";
@@ -8115,9 +8083,9 @@ compare_debug_dump_opt_spec_function (int arg,
 
       do_spec_1 (" ", 0, NULL);
 
-      gcc_assert (argbuf_index > 0);
+      gcc_assert (VEC_length (const_char_p, argbuf) > 0);
 
-      name = concat (argbuf[argbuf_index - 1], ext, NULL);
+      name = concat (VEC_last (const_char_p, argbuf), ext, NULL);
 
       ret = concat ("-fdump-final-insns=", name, NULL);
     }
@@ -8161,9 +8129,9 @@ compare_debug_self_opt_spec_function (int arg,
   do_spec_2 ("%{c|S:%{o*:%*}}");
   do_spec_1 (" ", 0, NULL);
 
-  if (argbuf_index > 0)
+  if (VEC_length (const_char_p, argbuf) > 0)
     debug_auxbase_opt = concat ("-auxbase-strip ",
-                               argbuf[argbuf_index - 1],
+                               VEC_last (const_char_p, argbuf),
                                NULL);
   else
     debug_auxbase_opt = NULL;
@@ -8216,3 +8184,46 @@ compare_debug_auxbase_opt_spec_function (int arg,
 
   return name;
 }
+
+/* %:pass-through-libs spec function.  Finds all -l options and input
+   file names in the lib spec passed to it, and makes a list of them
+   prepended with the plugin option to cause them to be passed through
+   to the final link after all the new object files have been added.  */
+
+const char *
+pass_through_libs_spec_func (int argc, const char **argv)
+{
+  char *prepended = xstrdup (" ");
+  int n;
+  /* Shlemiel the painter's algorithm.  Innately horrible, but at least
+     we know that there will never be more than a handful of strings to
+     concat, and it's only once per run, so it's not worth optimising.  */
+  for (n = 0; n < argc; n++)
+    {
+      char *old = prepended;
+      /* Anything that isn't an option is a full path to an output
+         file; pass it through if it ends in '.a'.  Among options,
+        pass only -l.  */
+      if (argv[n][0] == '-' && argv[n][1] == 'l')
+       {
+         const char *lopt = argv[n] + 2;
+         /* Handle both joined and non-joined -l options.  If for any
+            reason there's a trailing -l with no joined or following
+            arg just discard it.  */
+         if (!*lopt && ++n >= argc)
+           break;
+         else if (!*lopt)
+           lopt = argv[n];
+         prepended = concat (prepended, "-plugin-opt=-pass-through=-l",
+               lopt, " ", NULL);
+       }
+      else if (!strcmp (".a", argv[n] + strlen (argv[n]) - 2))
+       {
+         prepended = concat (prepended, "-plugin-opt=-pass-through=",
+               argv[n], " ", NULL);
+       }
+      if (prepended != old)
+       free (old);
+    }
+  return prepended;
+}