]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/collect2.c
[C++] Protect call to copy_attributes_to_builtin (PR91505)
[thirdparty/gcc.git] / gcc / collect2.c
index f0ab6b8c8f108e18f0c4a7c5474e99948b778fc0..e25e33962fb721f4d88c72b5ef1b3a29ff88aea8 100644 (file)
@@ -1,6 +1,6 @@
 /* Collect static initialization info into data structures that can be
    traversed by C++ initialization and finalization routines.
-   Copyright (C) 1992-2014 Free Software Foundation, Inc.
+   Copyright (C) 1992-2019 Free Software Foundation, Inc.
    Contributed by Chris Smith (csmith@convex.com).
    Heavily modified by Michael Meissner (meissner@cygnus.com),
    Per Bothner (bothner@cygnus.com), and John Gilmore (gnu@cygnus.com).
@@ -30,6 +30,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "filenames.h"
 #include "file-find.h"
+#include "simple-object.h"
+#include "lto-section-names.h"
 
 /* TARGET_64BIT may be defined to use driver specific functionality. */
 #undef TARGET_64BIT
@@ -43,6 +45,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "collect2.h"
 #include "collect2-aix.h"
+#include "collect-utils.h"
 #include "diagnostic.h"
 #include "demangle.h"
 #include "obstack.h"
@@ -175,7 +178,6 @@ struct head
   int number;
 };
 
-bool vflag;                            /* true if -v or --version */ 
 static int rflag;                      /* true if -r */
 static int strip_flag;                 /* true if -s */
 #ifdef COLLECT_EXPORT_LIST
@@ -198,13 +200,13 @@ static enum lto_mode_d lto_mode = LTO_MODE_WHOPR;
 static enum lto_mode_d lto_mode = LTO_MODE_NONE;
 #endif
 
-bool debug;                            /* true if -debug */
 bool helpflag;                 /* true if --help */
 
 static int shared_obj;                 /* true if -shared */
+static int static_obj;                 /* true if -static */
 
-static const char *c_file;             /* <xxx>.c for constructor/destructor list.  */
-static const char *o_file;             /* <xxx>.o for constructor/destructor list.  */
+static char *c_file;           /* <xxx>.c for constructor/destructor list.  */
+static char *o_file;           /* <xxx>.o for constructor/destructor list.  */
 #ifdef COLLECT_EXPORT_LIST
 static const char *export_file;                /* <xxx>.x for AIX export list.  */
 #endif
@@ -234,8 +236,7 @@ static struct head exports;         /* list of exported symbols */
 #endif
 static struct head frame_tables;       /* list of frame unwind info tables */
 
-static bool at_file_supplied;          /* Whether to use @file arguments */
-static char *response_file;            /* Name of any current response file */
+bool at_file_supplied;         /* Whether to use @file arguments */
 
 struct obstack temporary_obstack;
 char * temporary_firstobj;
@@ -257,6 +258,7 @@ bool may_unlink_output_file = false;
 #ifdef COLLECT_EXPORT_LIST
 /* Lists to keep libraries to be scanned for global constructors/destructors.  */
 static struct head libs;                    /* list of libraries */
+static struct head static_libs;             /* list of statically linked libraries */
 static struct path_prefix cmdline_lib_dirs; /* directories specified with -L */
 static struct path_prefix libpath_lib_dirs; /* directories in LIBPATH */
 static struct path_prefix *libpaths[3] = {&cmdline_lib_dirs,
@@ -284,7 +286,7 @@ static struct lto_object_list lto_objects;
 
 /* Special kinds of symbols that a name may denote.  */
 
-typedef enum {
+enum symkind {
   SYM_REGULAR = 0,  /* nothing special  */
 
   SYM_CTOR = 1,  /* constructor */
@@ -294,14 +296,13 @@ typedef enum {
   SYM_DWEH = 5,  /* DWARF exception handling table  */
   SYM_AIXI = 6,
   SYM_AIXD = 7
-} symkind;
+};
+
+const char tool_name[] = "collect2";
 
 static symkind is_ctor_dtor (const char *);
 
 static void handler (int);
-static void do_wait (const char *, struct pex_obj *);
-static void fork_execute (const char *, char **);
-static void maybe_unlink (const char *);
 static void maybe_unlink_list (char **);
 static void add_to_list (struct head *, const char *);
 static int extract_init_priority (const char *);
@@ -323,9 +324,7 @@ static void write_c_file_glob (FILE *, const char *);
 static void scan_libraries (const char *);
 #endif
 #ifdef COLLECT_EXPORT_LIST
-#if 0
 static int is_in_list (const char *, struct id *);
-#endif
 static void write_aix_file (FILE *, struct id *);
 static char *resolve_lib_name (const char *);
 #endif
@@ -336,13 +335,13 @@ static void process_args (int *argcp, char **argv);
 /* Enumerations describing which pass this is for scanning the
    program file ...  */
 
-typedef enum {
+enum scanpass {
   PASS_FIRST,                          /* without constructors */
   PASS_OBJ,                            /* individual objects */
   PASS_LIB,                            /* looking for shared libraries */
   PASS_SECOND,                         /* with constructors linked in */
   PASS_LTOINFO                         /* looking for objects with LTO info */
-} scanpass;
+};
 
 /* ... and which kinds of symbols are to be considered.  */
 
@@ -382,8 +381,8 @@ static void scan_prog_file (const char *, scanpass, scanfilter);
 \f
 /* Delete tempfiles and exit function.  */
 
-static void
-collect_atexit (void)
+void
+tool_cleanup (bool from_signal)
 {
   if (c_file != 0 && c_file[0])
     maybe_unlink (c_file);
@@ -401,32 +400,33 @@ collect_atexit (void)
 
   if (ldout != 0 && ldout[0])
     {
-      dump_ld_file (ldout, stdout);
+      if (!from_signal)
+       dump_ld_file (ldout, stdout);
       maybe_unlink (ldout);
     }
 
   if (lderrout != 0 && lderrout[0])
     {
-      dump_ld_file (lderrout, stderr);
+      if (!from_signal)
+       dump_ld_file (lderrout, stderr);
       maybe_unlink (lderrout);
     }
+}
 
-  if (response_file)
-    maybe_unlink (response_file);
+static void
+collect_atexit (void)
+{
+  tool_cleanup (false);
 }
 
-\f
-/* Notify user of a non-error.  */
-void
-notice (const char *cmsgid, ...)
+static void
+handler (int signo)
 {
-  va_list ap;
+  tool_cleanup (true);
 
-  va_start (ap, cmsgid);
-  vfprintf (stderr, _(cmsgid), ap);
-  va_end (ap);
+  signal (signo, SIG_DFL);
+  raise (signo);
 }
-
 /* Notify user of a non-error, without translating the format string.  */
 void
 notice_translated (const char *cmsgid, ...)
@@ -437,37 +437,6 @@ notice_translated (const char *cmsgid, ...)
   vfprintf (stderr, cmsgid, ap);
   va_end (ap);
 }
-\f
-static void
-handler (int signo)
-{
-  if (c_file != 0 && c_file[0])
-    maybe_unlink (c_file);
-
-  if (o_file != 0 && o_file[0])
-    maybe_unlink (o_file);
-
-  if (ldout != 0 && ldout[0])
-    maybe_unlink (ldout);
-
-  if (lderrout != 0 && lderrout[0])
-    maybe_unlink (lderrout);
-
-#ifdef COLLECT_EXPORT_LIST
-  if (export_file != 0 && export_file[0])
-    maybe_unlink (export_file);
-#endif
-
-  if (lto_o_files)
-    maybe_unlink_list (lto_o_files);
-
-  if (response_file)
-    maybe_unlink (response_file);
-
-  signal (signo, SIG_DFL);
-  raise (signo);
-}
-
 \f
 int
 file_exists (const char *name)
@@ -732,7 +701,8 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst,
       size_t num_files;
 
       if (!lto_wrapper)
-       fatal_error ("COLLECT_LTO_WRAPPER must be set");
+       fatal_error (input_location, "environment variable "
+                    "%<COLLECT_LTO_WRAPPER%> must be set");
 
       num_lto_c_args++;
 
@@ -755,7 +725,8 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst,
       *lto_c_ptr = NULL;
 
       /* Run the LTO back end.  */
-      pex = collect_execute (prog, lto_c_argv, NULL, NULL, PEX_SEARCH);
+      pex = collect_execute (prog, lto_c_argv, NULL, NULL, PEX_SEARCH,
+                            at_file_supplied);
       {
        int c;
        FILE *stream;
@@ -793,7 +764,7 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst,
       do_wait (prog, pex);
       pex = NULL;
 
-      /* Compute memory needed for new LD arguments.  At most number of original arguemtns
+      /* Compute memory needed for new LD arguments.  At most number of original arguments
         plus number of partitions.  */
       for (lto_ld_argv_size = 0; lto_ld_argv[lto_ld_argv_size]; lto_ld_argv_size++)
        ;
@@ -835,8 +806,10 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst,
 
       /* Run the linker again, this time replacing the object files
          optimized by the LTO with the temporary file generated by the LTO.  */
-      fork_execute ("ld", out_lto_ld_argv);
-      post_ld_pass (true);
+      fork_execute ("ld", out_lto_ld_argv, HAVE_GNU_LD && at_file_supplied);
+      /* We assume that temp files were created, and therefore we need to take
+         that into account (maybe run dsymutil).  */
+      post_ld_pass (/*temp_file*/true);
       free (lto_ld_argv);
 
       maybe_unlink_list (lto_o_files);
@@ -845,9 +818,12 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst,
     {
       /* Our caller is relying on us to do the link
          even though there is no LTO back end work to be done.  */
-      fork_execute ("ld", lto_ld_argv);
-      post_ld_pass (false);
+      fork_execute ("ld", lto_ld_argv, HAVE_GNU_LD && at_file_supplied);
+      /* No LTO objects were found, so no new temp file.  */
+      post_ld_pass (/*temp_file*/false);
     }
+  else
+    post_ld_pass (false); /* No LTO objects were found, no temp file.  */
 }
 \f
 /* Main program.  */
@@ -861,6 +837,7 @@ main (int argc, char **argv)
       USE_PLUGIN_LD,
       USE_GOLD_LD,
       USE_BFD_LD,
+      USE_LLD_LD,
       USE_LD_MAX
     } selected_linker = USE_DEFAULT_LD;
   static const char *const ld_suffixes[USE_LD_MAX] =
@@ -868,7 +845,8 @@ main (int argc, char **argv)
       "ld",
       PLUGIN_LD_SUFFIX,
       "ld.gold",
-      "ld.bfd"
+      "ld.bfd",
+      "ld.lld"
     };
   static const char *const real_ld_suffix = "real-ld";
   static const char *const collect_ld_suffix = "collect-ld";
@@ -941,6 +919,9 @@ main (int argc, char **argv)
   int first_file;
   int num_c_args;
   char **old_argv;
+#ifdef COLLECT_EXPORT_LIST
+  bool is_static = false;
+#endif
   int i;
 
   for (i = 0; i < USE_LD_MAX; i++)
@@ -985,9 +966,6 @@ main (int argc, char **argv)
   signal (SIGCHLD, SIG_DFL);
 #endif
 
-  if (atexit (collect_atexit) != 0)
-    fatal_error ("atexit failed");
-
   /* Unlock the stdio streams.  */
   unlock_std_streams ();
 
@@ -995,6 +973,9 @@ main (int argc, char **argv)
 
   diagnostic_initialize (global_dc, 0);
 
+  if (atexit (collect_atexit) != 0)
+    fatal_error (input_location, "atexit failed");
+
   /* Do not invoke xcalloc before this point, since locale needs to be
      set first, in case a diagnostic is issued.  */
 
@@ -1006,13 +987,21 @@ main (int argc, char **argv)
   object = CONST_CAST2 (const char **, char **, object_lst);
 
 #ifdef DEBUG
-  debug = 1;
+  debug = true;
+#endif
+
+  save_temps = false;
+  verbose = false;
+
+#ifndef DEFAULT_A_OUT_NAME
+  output_file = "a.out";
+#else
+  output_file = DEFAULT_A_OUT_NAME;
 #endif
 
-  /* Parse command line early for instances of -debug.  This allows
-     the debug flag to be set before functions like find_a_file()
-     are called.  We also look for the -flto or -flto-partition=none flag to know
-     what LTO mode we are in.  */
+  /* Parse command line / environment for flags we want early.
+     This allows the debug flag to be set before functions like find_a_file()
+     are called. */
   {
     bool no_partition = false;
 
@@ -1020,8 +1009,6 @@ main (int argc, char **argv)
       {
        if (! strcmp (argv[i], "-debug"))
          debug = true;
-        else if (! strcmp (argv[i], "-flto-partition=none"))
-         no_partition = true;
        else if (!strncmp (argv[i], "-fno-lto", 8))
          lto_mode = LTO_MODE_NONE;
         else if (! strcmp (argv[i], "-plugin"))
@@ -1034,6 +1021,17 @@ main (int argc, char **argv)
          selected_linker = USE_BFD_LD;
        else if (strcmp (argv[i], "-fuse-ld=gold") == 0)
          selected_linker = USE_GOLD_LD;
+       else if (strcmp (argv[i], "-fuse-ld=lld") == 0)
+         selected_linker = USE_LLD_LD;
+       else if (strncmp (argv[i], "-o", 2) == 0)
+         {
+           /* Parse the output filename if it's given so that we can make
+              meaningful temp filenames.  */
+           if (argv[i][2] == '\0')
+             output_file = argv[i+1];
+           else
+             output_file = &argv[i][2];
+         }
 
 #ifdef COLLECT_EXPORT_LIST
        /* These flags are position independent, although their order
@@ -1054,34 +1052,41 @@ main (int argc, char **argv)
            aixlazy_flag = 1;
 #endif
       }
-    vflag = debug;
-    find_file_set_debug (debug);
-    if (use_plugin)
-      lto_mode = LTO_MODE_NONE;
-    if (no_partition && lto_mode == LTO_MODE_WHOPR)
-      lto_mode = LTO_MODE_LTO;
-  }
 
-#ifndef DEFAULT_A_OUT_NAME
-  output_file = "a.out";
-#else
-  output_file = DEFAULT_A_OUT_NAME;
-#endif
-
-  obstack_begin (&temporary_obstack, 0);
-  temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0);
+    obstack_begin (&temporary_obstack, 0);
+    temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0);
 
 #ifndef HAVE_LD_DEMANGLE
   current_demangling_style = auto_demangling;
 #endif
-  p = getenv ("COLLECT_GCC_OPTIONS");
-  while (p && *p)
-    {
-      const char *q = extract_string (&p);
-      if (*q == '-' && (q[1] == 'm' || q[1] == 'f'))
-       num_c_args++;
+
+    /* Now pick up any flags we want early from COLLECT_GCC_OPTIONS
+       The LTO options are passed here as are other options that might
+       be unsuitable for ld (e.g. -save-temps).  */
+    p = getenv ("COLLECT_GCC_OPTIONS");
+    while (p && *p)
+      {
+       const char *q = extract_string (&p);
+       if (*q == '-' && (q[1] == 'm' || q[1] == 'f'))
+         num_c_args++;
+       if (strncmp (q, "-flto-partition=none", 20) == 0)
+         no_partition = true;
+       else if (strncmp (q, "-fno-lto", 8) == 0)
+         lto_mode = LTO_MODE_NONE;
+       else if (strncmp (q, "-save-temps", 11) == 0)
+         /* FIXME: Honour =obj.  */
+         save_temps = true;
     }
-  obstack_free (&temporary_obstack, temporary_firstobj);
+    obstack_free (&temporary_obstack, temporary_firstobj);
+
+    verbose = verbose || debug;
+    save_temps = save_temps || debug;
+    find_file_set_debug (debug);
+    if (use_plugin)
+      lto_mode = LTO_MODE_NONE;
+    if (no_partition && lto_mode == LTO_MODE_WHOPR)
+      lto_mode = LTO_MODE_LTO;
+  }
 
   /* -fno-profile-arcs -fno-test-coverage -fno-branch-probabilities
      -fno-exceptions -w -fno-whole-program */
@@ -1091,7 +1096,7 @@ main (int argc, char **argv)
   c_ptr = CONST_CAST2 (const char **, char **, c_argv);
 
   if (argc < 2)
-    fatal_error ("no arguments");
+    fatal_error (input_location, "no arguments");
 
 #ifdef SIGQUIT
   if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
@@ -1123,7 +1128,8 @@ main (int argc, char **argv)
   /* Maybe we know the right file to use (if not cross).  */
   ld_file_name = 0;
 #ifdef DEFAULT_LINKER
-  if (selected_linker == USE_BFD_LD || selected_linker == USE_GOLD_LD)
+  if (selected_linker == USE_BFD_LD || selected_linker == USE_GOLD_LD ||
+      selected_linker == USE_LLD_LD)
     {
       char *linker_name;
 # ifdef HOST_EXECUTABLE_SUFFIX
@@ -1230,8 +1236,22 @@ main (int argc, char **argv)
   *ld1++ = *ld2++ = ld_file_name;
 
   /* Make temp file names.  */
-  c_file = make_temp_file (".c");
-  o_file = make_temp_file (".o");
+  if (save_temps)
+    {
+      c_file = (char *) xmalloc (strlen (output_file)
+                                 + sizeof (".cdtor.c") + 1);
+      strcpy (c_file, output_file);
+      strcat (c_file, ".cdtor.c");
+      o_file = (char *) xmalloc (strlen (output_file)
+                                 + sizeof (".cdtor.o") + 1);
+      strcpy (o_file, output_file);
+      strcat (o_file, ".cdtor.o");
+    }
+  else
+    {
+      c_file = make_temp_file (".cdtor.c");
+      o_file = make_temp_file (".cdtor.o");
+    }
 #ifdef COLLECT_EXPORT_LIST
   export_file = make_temp_file (".x");
 #endif
@@ -1240,6 +1260,7 @@ main (int argc, char **argv)
       ldout = make_temp_file (".ld");
       lderrout = make_temp_file (".le");
     }
+  /* Build the command line to compile the ctor/dtor list.  */
   *c_ptr++ = c_file_name;
   *c_ptr++ = "-x";
   *c_ptr++ = "c";
@@ -1271,6 +1292,8 @@ main (int argc, char **argv)
        *c_ptr++ = xstrdup (q);
       if (strcmp (q, "-shared") == 0)
        shared_obj = 1;
+      if (strcmp (q, "-static") == 0)
+       static_obj = 1;
       if (*q == '-' && q[1] == 'B')
        {
          *c_ptr++ = xstrdup (q);
@@ -1299,6 +1322,9 @@ main (int argc, char **argv)
   /* Parse arguments.  Remember output file spec, pass the rest to ld.  */
   /* After the first file, put in the c++ rt0.  */
 
+#ifdef COLLECT_EXPORT_LIST
+  is_static = static_obj;
+#endif
   first_file = 1;
   while ((arg = *++argv) != (char *) 0)
     {
@@ -1337,7 +1363,13 @@ main (int argc, char **argv)
              else if (!use_collect_ld
                       && strncmp (arg, "-fuse-ld=", 9) == 0)
                {
-                 /* Do not pass -fuse-ld={bfd|gold} to the linker. */
+                 /* Do not pass -fuse-ld={bfd|gold|lld} to the linker. */
+                 ld1--;
+                 ld2--;
+               }
+             else if (strncmp (arg, "-fno-lto", 8) == 0)
+               {
+                 /* Do not pass -fno-lto to the linker. */
                  ld1--;
                  ld2--;
                }
@@ -1365,7 +1397,8 @@ main (int argc, char **argv)
 
                  stream = fopen (list_filename, "r");
                  if (stream == NULL)
-                   fatal_error ("can't open %s: %m", list_filename);
+                   fatal_error (input_location, "cannot open %s: %m",
+                                list_filename);
 
                  while (fgets (buf, sizeof buf, stream) != NULL)
                    {
@@ -1397,6 +1430,18 @@ main (int argc, char **argv)
 #endif
               break;
 
+#ifdef COLLECT_EXPORT_LIST
+           case 'b':
+             if (!strcmp (arg, "-bstatic"))
+               {
+                 is_static = true;
+               }
+             else if (!strcmp (arg, "-bdynamic") || !strcmp (arg, "-bshared"))
+               {
+                 is_static = false;
+               }
+             break;
+#endif
            case 'l':
              if (first_file)
                {
@@ -1413,6 +1458,8 @@ main (int argc, char **argv)
 
                /* Saving a full library name.  */
                add_to_list (&libs, s);
+               if (is_static)
+                   add_to_list (&static_libs, s);
              }
 #endif
              break;
@@ -1449,7 +1496,7 @@ main (int argc, char **argv)
 
            case 'v':
              if (arg[2] == '\0')
-               vflag = true;
+               verbose = true;
              break;
 
            case '-':
@@ -1470,7 +1517,7 @@ main (int argc, char **argv)
                      enum demangling_styles style
                        = cplus_demangle_name_to_style (arg+11);
                      if (style == unknown_demangling)
-                       error ("unknown demangling style '%s'", arg+11);
+                       error ("unknown demangling style %qs", arg+11);
                      else
                        current_demangling_style = style;
                    }
@@ -1481,7 +1528,7 @@ main (int argc, char **argv)
              else if (strncmp (arg, "--sysroot=", 10) == 0)
                target_system_root = arg + 10;
              else if (strcmp (arg, "--version") == 0)
-               vflag = true;
+               verbose = true;
              else if (strcmp (arg, "--help") == 0)
                helpflag = true;
              break;
@@ -1513,6 +1560,8 @@ main (int argc, char **argv)
            {
              /* Saving a full library name.  */
              add_to_list (&libs, arg);
+             if (is_static)
+               add_to_list (&static_libs, arg);
            }
 #endif
        }
@@ -1524,6 +1573,8 @@ main (int argc, char **argv)
     {
       fprintf (stderr, "List of libraries:\n");
       dump_list (stderr, "\t", libs.first);
+      fprintf (stderr, "List of statically linked libraries:\n");
+      dump_list (stderr, "\t", static_libs.first);
     }
 
   /* The AIX linker will discard static constructors in object files if
@@ -1548,9 +1599,11 @@ main (int argc, char **argv)
       this_filter &= ~SCAN_DWEH;
 #endif
 
+    /* Scan object files.  */
     while (export_object_lst < object)
       scan_prog_file (*export_object_lst++, PASS_OBJ, this_filter);
 
+    /* Scan libraries.  */
     for (; list; list = list->next)
       scan_prog_file (list->name, PASS_FIRST, this_filter);
 
@@ -1566,17 +1619,17 @@ main (int argc, char **argv)
 
       exportf = fopen (export_file, "w");
       if (exportf == (FILE *) 0)
-       fatal_error ("fopen %s: %m", export_file);
+       fatal_error (input_location, "fopen %s: %m", export_file);
       write_aix_file (exportf, exports.first);
       if (fclose (exportf))
-       fatal_error ("fclose %s: %m", export_file);
+       fatal_error (input_location, "fclose %s: %m", export_file);
     }
 #endif
 
   *c_ptr++ = c_file;
   *c_ptr = *ld1 = *object = (char *) 0;
 
-  if (vflag)
+  if (verbose)
     notice ("collect2 version %s\n", version_string);
 
   if (helpflag)
@@ -1588,7 +1641,7 @@ main (int argc, char **argv)
       printf ("  --help          Display this information\n");
       printf ("  -v, --version   Display this program's version number\n");
       printf ("\n");
-      printf ("Overview: http://gcc.gnu.org/onlinedocs/gccint/Collect2.html\n");
+      printf ("Overview: https://gcc.gnu.org/onlinedocs/gccint/Collect2.html\n");
       printf ("Report bugs: %s\n", bug_report_url);
       printf ("\n");
     }
@@ -1663,10 +1716,8 @@ main (int argc, char **argv)
        if (lto_mode != LTO_MODE_NONE)
          maybe_run_lto_and_relink (ld1_argv, object_lst, object, false);
        else
-         post_ld_pass (false);
+         post_ld_pass (/*temp_file*/false);
 
-       maybe_unlink (c_file);
-       maybe_unlink (o_file);
        return 0;
       }
   }
@@ -1729,13 +1780,13 @@ main (int argc, char **argv)
          strip_argv[0] = strip_file_name;
          strip_argv[1] = output_file;
          strip_argv[2] = (char *) 0;
-         fork_execute ("strip", real_strip_argv);
+         fork_execute ("strip", real_strip_argv, false);
        }
 
 #ifdef COLLECT_EXPORT_LIST
       maybe_unlink (export_file);
 #endif
-      post_ld_pass (false);
+      post_ld_pass (/*temp_file*/false);
 
       maybe_unlink (c_file);
       maybe_unlink (o_file);
@@ -1749,12 +1800,12 @@ main (int argc, char **argv)
   maybe_unlink (output_file);
   outf = fopen (c_file, "w");
   if (outf == (FILE *) 0)
-    fatal_error ("fopen %s: %m", c_file);
+    fatal_error (input_location, "fopen %s: %m", c_file);
 
   write_c_file (outf, c_file);
 
   if (fclose (outf))
-    fatal_error ("fclose %s: %m", c_file);
+    fatal_error (input_location, "fclose %s: %m", c_file);
 
   /* Tell the linker that we have initializer and finalizer functions.  */
 #ifdef LD_INIT_SWITCH
@@ -1789,10 +1840,10 @@ main (int argc, char **argv)
 #endif
       exportf = fopen (export_file, "w");
       if (exportf == (FILE *) 0)
-       fatal_error ("fopen %s: %m", export_file);
+       fatal_error (input_location, "fopen %s: %m", export_file);
       write_aix_file (exportf, exports.first);
       if (fclose (exportf))
-       fatal_error ("fclose %s: %m", export_file);
+       fatal_error (input_location, "fclose %s: %m", export_file);
     }
 #endif
 
@@ -1815,7 +1866,7 @@ main (int argc, char **argv)
   /* Assemble the constructor and destructor tables.
      Link the tables in with the rest of the program.  */
 
-  fork_execute ("gcc",  c_argv);
+  fork_execute ("gcc",  c_argv, at_file_supplied);
 #ifdef COLLECT_EXPORT_LIST
   /* On AIX we must call tlink because of possible templates resolution.  */
   do_tlink (ld2_argv, object_lst);
@@ -1828,8 +1879,8 @@ main (int argc, char **argv)
     maybe_run_lto_and_relink (ld2_argv, object_lst, object, true);
   else
     {
-      fork_execute ("ld", ld2_argv);
-      post_ld_pass (false);
+      fork_execute ("ld", ld2_argv, HAVE_GNU_LD && at_file_supplied);
+      post_ld_pass (/*temp_file*/false);
     }
 
   /* Let scan_prog_file do any final mods (OSF/rose needs this for
@@ -1847,169 +1898,17 @@ main (int argc, char **argv)
   return 0;
 }
 
-\f
-/* Wait for a process to finish, and exit if a nonzero status is found.  */
-
-int
-collect_wait (const char *prog, struct pex_obj *pex)
-{
-  int status;
-
-  if (!pex_get_status (pex, 1, &status))
-    fatal_error ("can't get program status: %m");
-  pex_free (pex);
-
-  if (status)
-    {
-      if (WIFSIGNALED (status))
-       {
-         int sig = WTERMSIG (status);
-         error ("%s terminated with signal %d [%s]%s",
-                prog, sig, strsignal (sig),
-                WCOREDUMP (status) ? ", core dumped" : "");
-         exit (FATAL_EXIT_CODE);
-       }
-
-      if (WIFEXITED (status))
-       return WEXITSTATUS (status);
-    }
-  return 0;
-}
-
-static void
-do_wait (const char *prog, struct pex_obj *pex)
-{
-  int ret = collect_wait (prog, pex);
-  if (ret != 0)
-    {
-      error ("%s returned %d exit status", prog, ret);
-      exit (ret);
-    }
-
-  if (response_file)
-    {
-      unlink (response_file);
-      response_file = NULL;
-    }
-}
-
-\f
-/* Execute a program, and wait for the reply.  */
-
-struct pex_obj *
-collect_execute (const char *prog, char **argv, const char *outname,
-                const char *errname, int flags)
-{
-  struct pex_obj *pex;
-  const char *errmsg;
-  int err;
-  char *response_arg = NULL;
-  char *response_argv[3] ATTRIBUTE_UNUSED;
-
-  if (HAVE_GNU_LD && at_file_supplied && argv[0] != NULL)
-    {
-      /* If using @file arguments, create a temporary file and put the
-         contents of argv into it.  Then change argv to an array corresponding
-         to a single argument @FILE, where FILE is the temporary filename.  */
-
-      char **current_argv = argv + 1;
-      char *argv0 = argv[0];
-      int status;
-      FILE *f;
-
-      /* Note: we assume argv contains at least one element; this is
-         checked above.  */
-
-      response_file = make_temp_file ("");
-
-      f = fopen (response_file, "w");
-
-      if (f == NULL)
-        fatal_error ("could not open response file %s", response_file);
-
-      status = writeargv (current_argv, f);
-
-      if (status)
-        fatal_error ("could not write to response file %s", response_file);
-
-      status = fclose (f);
-
-      if (EOF == status)
-        fatal_error ("could not close response file %s", response_file);
-
-      response_arg = concat ("@", response_file, NULL);
-      response_argv[0] = argv0;
-      response_argv[1] = response_arg;
-      response_argv[2] = NULL;
-
-      argv = response_argv;
-    }
-
-  if (vflag || debug)
-    {
-      char **p_argv;
-      const char *str;
-
-      if (argv[0])
-       fprintf (stderr, "%s", argv[0]);
-      else
-       notice ("[cannot find %s]", prog);
-
-      for (p_argv = &argv[1]; (str = *p_argv) != (char *) 0; p_argv++)
-       fprintf (stderr, " %s", str);
-
-      fprintf (stderr, "\n");
-    }
-
-  fflush (stdout);
-  fflush (stderr);
-
-  /* If we cannot find a program we need, complain error.  Do this here
-     since we might not end up needing something that we could not find.  */
-
-  if (argv[0] == 0)
-    fatal_error ("cannot find '%s'", prog);
-
-  pex = pex_init (0, "collect2", NULL);
-  if (pex == NULL)
-    fatal_error ("pex_init failed: %m");
-
-  errmsg = pex_run (pex, flags, argv[0], argv, outname,
-                   errname, &err);
-  if (errmsg != NULL)
-    {
-      if (err != 0)
-       {
-         errno = err;
-         fatal_error ("%s: %m", _(errmsg));
-       }
-      else
-       fatal_error (errmsg);
-    }
-
-  free (response_arg);
-
-  return pex;
-}
-
-static void
-fork_execute (const char *prog, char **argv)
-{
-  struct pex_obj *pex;
-
-  pex = collect_execute (prog, argv, NULL, NULL, PEX_LAST | PEX_SEARCH);
-  do_wait (prog, pex);
-}
 \f
 /* Unlink FILE unless we are debugging or this is the output_file
    and we may not unlink it.  */
 
-static void
+void
 maybe_unlink (const char *file)
 {
-  if (debug)
+  if (save_temps && file_exists (file))
     {
-      notice ("[Leaving %s]\n", file);
+      if (verbose)
+       notice ("[Leaving %s]\n", file);
       return;
     }
 
@@ -2151,7 +2050,6 @@ write_list (FILE *stream, const char *prefix, struct id *list)
 
 #ifdef COLLECT_EXPORT_LIST
 /* This function is really used only on AIX, but may be useful.  */
-#if 0
 static int
 is_in_list (const char *prefix, struct id *list)
 {
@@ -2162,7 +2060,6 @@ is_in_list (const char *prefix, struct id *list)
     }
     return 0;
 }
-#endif
 #endif /* COLLECT_EXPORT_LIST */
 
 /* Added for debugging purpose.  */
@@ -2284,12 +2181,23 @@ write_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED)
       fprintf (stream, "  struct object *next;\n");
       fprintf (stream, "};\n");
 
+      fprintf (stream, "extern void __register_frame_info_table_bases (void *, struct object *, void *tbase, void *dbase);\n");
       fprintf (stream, "extern void __register_frame_info_table (void *, struct object *);\n");
       fprintf (stream, "extern void *__deregister_frame_info (void *);\n");
+#ifdef TARGET_AIX_VERSION
+      fprintf (stream, "extern void *__gcc_unwind_dbase;\n");
+#endif
 
       fprintf (stream, "static void reg_frame () {\n");
       fprintf (stream, "\tstatic struct object ob;\n");
+#ifdef TARGET_AIX_VERSION
+      /* Use __gcc_unwind_dbase as the base address for data on AIX.
+        This might not be the start of the segment, signed offsets assumed.
+       */
+      fprintf (stream, "\t__register_frame_info_table_bases (frame_table, &ob, (void *)0, &__gcc_unwind_dbase);\n");
+#else
       fprintf (stream, "\t__register_frame_info_table (frame_table, &ob);\n");
+#endif
       fprintf (stream, "\t}\n");
 
       fprintf (stream, "static void dereg_frame () {\n");
@@ -2430,38 +2338,52 @@ write_aix_file (FILE *stream, struct id *list)
 
 /* Check to make sure the file is an LTO object file.  */
 
+static int
+has_lto_section (void *data, const char *name ATTRIBUTE_UNUSED,
+                off_t offset ATTRIBUTE_UNUSED,
+                off_t length ATTRIBUTE_UNUSED)
+{
+  int *found = (int *) data;
+
+  if (strncmp (name, LTO_SECTION_NAME_PREFIX,
+              sizeof (LTO_SECTION_NAME_PREFIX) - 1) != 0)
+    {
+      if (strncmp (name, OFFLOAD_SECTION_NAME_PREFIX,
+                  sizeof (OFFLOAD_SECTION_NAME_PREFIX) - 1) != 0)
+        return 1;
+    }
+
+  *found = 1;
+
+  /* Stop iteration.  */
+  return 0;
+}
+
 static bool
-maybe_lto_object_file (const char *prog_name)
+is_lto_object_file (const char *prog_name)
 {
-  FILE *f;
-  unsigned char buf[4];
-  int i;
+  const char *errmsg;
+  int err;
+  int found = 0;
+  off_t inoff = 0;
+  int infd = open (prog_name, O_RDONLY | O_BINARY);
 
-  static unsigned char elfmagic[4] = { 0x7f, 'E', 'L', 'F' };
-  static unsigned char coffmagic[2] = { 0x4c, 0x01 };
-  static unsigned char coffmagic_x64[2] = { 0x64, 0x86 };
-  static unsigned char machomagic[4][4] = {
-    { 0xcf, 0xfa, 0xed, 0xfe },
-    { 0xce, 0xfa, 0xed, 0xfe },
-    { 0xfe, 0xed, 0xfa, 0xcf },
-    { 0xfe, 0xed, 0xfa, 0xce }
-  };
+  if (infd == -1)
+    return false;
 
-  f = fopen (prog_name, "rb");
-  if (f == NULL)
+  simple_object_read *inobj = simple_object_start_read (infd, inoff,
+                                                       LTO_SEGMENT_NAME,
+                                                       &errmsg, &err);
+  if (!inobj)
     return false;
-  if (fread (buf, sizeof (buf), 1, f) != 1)
-    buf[0] = 0;
-  fclose (f);
 
-  if (memcmp (buf, elfmagic, sizeof (elfmagic)) == 0
-      || memcmp (buf, coffmagic, sizeof (coffmagic)) == 0
-      || memcmp (buf, coffmagic_x64, sizeof (coffmagic_x64)) == 0)
+  errmsg = simple_object_find_sections (inobj, has_lto_section,
+                                       (void *) &found, &err);
+  if (! errmsg && found)
     return true;
-  for (i = 0; i < 4; i++)
-    if (memcmp (buf, machomagic[i], sizeof (machomagic[i])) == 0)
-      return true;
 
+  if (errmsg)
+    fatal_error (0, "%s: %s", errmsg, xstrerror (err));
   return false;
 }
 
@@ -2484,7 +2406,6 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
   int err;
   char *p, buf[1024];
   FILE *inf;
-  int found_lto = 0;
 
   if (which_pass == PASS_SECOND)
     return;
@@ -2492,12 +2413,17 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
   /* LTO objects must be in a known format.  This check prevents
      us from accepting an archive containing LTO objects, which
      gcc cannot currently handle.  */
-  if (which_pass == PASS_LTOINFO && !maybe_lto_object_file (prog_name))
-    return;
+  if (which_pass == PASS_LTOINFO)
+    {
+      if(is_lto_object_file (prog_name)) {
+       add_lto_object (&lto_objects, prog_name);
+      }
+      return;
+    }
 
   /* If we do not have an `nm', complain.  */
   if (nm_file_name == 0)
-    fatal_error ("cannot find 'nm'");
+    fatal_error (input_location, "cannot find %<nm%>");
 
   nm_argv[argc++] = nm_file_name;
   if (NM_FLAGS[0] != '\0')
@@ -2507,7 +2433,7 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
   nm_argv[argc++] = (char *) 0;
 
   /* Trace if needed.  */
-  if (vflag)
+  if (verbose)
     {
       const char **p_argv;
       const char *str;
@@ -2523,7 +2449,7 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
 
   pex = pex_init (PEX_USE_PIPES, "collect2", NULL);
   if (pex == NULL)
-    fatal_error ("pex_init failed: %m");
+    fatal_error (input_location, "%<pex_init%> failed: %m");
 
   errmsg = pex_run (pex, 0, nm_file_name, real_nm_argv, NULL, HOST_BIT_BUCKET,
                    &err);
@@ -2532,10 +2458,10 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
       if (err != 0)
        {
          errno = err;
-         fatal_error ("%s: %m", _(errmsg));
+         fatal_error (input_location, "%s: %m", _(errmsg));
        }
       else
-       fatal_error (errmsg);
+       fatal_error (input_location, errmsg);
     }
 
   int_handler  = (void (*) (int)) signal (SIGINT,  SIG_IGN);
@@ -2545,15 +2471,10 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
 
   inf = pex_read_output (pex, 0);
   if (inf == NULL)
-    fatal_error ("can't open nm output: %m");
+    fatal_error (input_location, "cannot open nm output: %m");
 
   if (debug)
-    {
-      if (which_pass == PASS_LTOINFO)
-        fprintf (stderr, "\nnm output with LTO info marker symbol.\n");
-      else
-        fprintf (stderr, "\nnm output with constructors/destructors.\n");
-    }
+    fprintf (stderr, "\nnm output with constructors/destructors.\n");
 
   /* Read each line of nm output.  */
   while (fgets (buf, sizeof buf, inf) != (char *) 0)
@@ -2564,30 +2485,6 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
       if (debug)
         fprintf (stderr, "\t%s\n", buf);
 
-      if (which_pass == PASS_LTOINFO)
-        {
-          if (found_lto)
-            continue;
-
-          /* Look for the LTO info marker symbol, and add filename to
-             the LTO objects list if found.  */
-          for (p = buf; (ch = *p) != '\0' && ch != '\n'; p++)
-            if (ch == ' '  && p[1] == '_' && p[2] == '_'
-               && (strncmp (p + (p[3] == '_' ? 2 : 1), "__gnu_lto_v1", 12) == 0)
-               && ISSPACE (p[p[3] == '_' ? 14 : 13]))
-              {
-                add_lto_object (&lto_objects, prog_name);
-
-                /* We need to read all the input, so we can't just
-                   return here.  But we can avoid useless work.  */
-                found_lto = 1;
-
-                break;
-              }
-
-         continue;
-        }
-
       /* If it contains a constructor or destructor name, add the name
         to the appropriate list unless this is a kind of symbol we're
         not supposed to even consider.  */
@@ -2629,7 +2526,8 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
          if (! (filter & SCAN_INIT))
            break;
          if (which_pass != PASS_LIB)
-           fatal_error ("init function found in object %s", prog_name);
+           fatal_error (input_location, "init function found in object %s",
+                        prog_name);
 #ifndef LD_INIT_SWITCH
          add_to_list (&constructors, name);
 #endif
@@ -2639,7 +2537,8 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
          if (! (filter & SCAN_FINI))
            break;
          if (which_pass != PASS_LIB)
-           fatal_error ("fini function found in object %s", prog_name);
+           fatal_error (input_location, "fini function found in object %s",
+                        prog_name);
 #ifndef LD_FINI_SWITCH
          add_to_list (&destructors, name);
 #endif
@@ -2695,7 +2594,7 @@ scan_libraries (const char *prog_name)
   /* If we do not have an `ldd', complain.  */
   if (ldd_file_name == 0)
     {
-      error ("cannot find 'ldd'");
+      error ("cannot find %<ldd%>");
       return;
     }
 
@@ -2704,7 +2603,7 @@ scan_libraries (const char *prog_name)
   ldd_argv[argc++] = (char *) 0;
 
   /* Trace if needed.  */
-  if (vflag)
+  if (verbose)
     {
       const char **p_argv;
       const char *str;
@@ -2720,7 +2619,7 @@ scan_libraries (const char *prog_name)
 
   pex = pex_init (PEX_USE_PIPES, "collect2", NULL);
   if (pex == NULL)
-    fatal_error ("pex_init failed: %m");
+    fatal_error (input_location, "pex_init failed: %m");
 
   errmsg = pex_run (pex, 0, ldd_file_name, real_ldd_argv, NULL, NULL, &err);
   if (errmsg != NULL)
@@ -2728,10 +2627,10 @@ scan_libraries (const char *prog_name)
       if (err != 0)
        {
          errno = err;
-         fatal_error ("%s: %m", _(errmsg));
+         fatal_error (input_location, "%s: %m", _(errmsg));
        }
       else
-       fatal_error (errmsg);
+       fatal_error (input_location, errmsg);
     }
 
   int_handler  = (void (*) (int)) signal (SIGINT,  SIG_IGN);
@@ -2741,7 +2640,7 @@ scan_libraries (const char *prog_name)
 
   inf = pex_read_output (pex, 0);
   if (inf == NULL)
-    fatal_error ("can't open ldd output: %m");
+    fatal_error (input_location, "cannot open ldd output: %m");
 
   if (debug)
     notice ("\nldd output with constructors/destructors.\n");
@@ -2759,7 +2658,7 @@ scan_libraries (const char *prog_name)
 
       name = p;
       if (strncmp (name, "not found", sizeof ("not found") - 1) == 0)
-       fatal_error ("dynamic dependency %s not found", buf);
+       fatal_error (input_location, "dynamic dependency %s not found", buf);
 
       /* Find the end of the symbol name.  */
       for (end = p;
@@ -2771,7 +2670,8 @@ scan_libraries (const char *prog_name)
       if (access (name, R_OK) == 0)
        add_to_list (&libraries, name);
       else
-       fatal_error ("unable to open dynamic dependency '%s'", buf);
+       fatal_error (input_location, "unable to open dynamic dependency "
+                    "%qs", buf);
 
       if (debug)
        fprintf (stderr, "\t%s\n", buf);
@@ -2803,17 +2703,6 @@ scan_libraries (const char *prog_name)
 
 #ifdef OBJECT_FORMAT_COFF
 
-#if defined (EXTENDED_COFF)
-
-#   define GCC_SYMBOLS(X)      (SYMHEADER (X).isymMax + SYMHEADER (X).iextMax)
-#   define GCC_SYMENT          SYMR
-#   define GCC_OK_SYMBOL(X)    ((X).st == stProc || (X).st == stGlobal)
-#   define GCC_SYMINC(X)       (1)
-#   define GCC_SYMZERO(X)      (SYMHEADER (X).isymMax)
-#   define GCC_CHECK_HDR(X)    (PSYMTAB (X) != 0)
-
-#else
-
 #   define GCC_SYMBOLS(X)      (HEADER (ldptr).f_nsyms)
 #   define GCC_SYMENT          SYMENT
 #   if defined (C_WEAKEXT)
@@ -2852,8 +2741,6 @@ scan_libraries (const char *prog_name)
       && !(HEADER (X).f_flags & F_LOADONLY))
 #endif
 
-#endif
-
 #ifdef COLLECT_EXPORT_LIST
 /* Array of standard AIX libraries which should not
    be scanned for ctors/dtors.  */
@@ -2934,7 +2821,7 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
       if ((ldptr = ldopen (CONST_CAST (char *, prog_name), ldptr)) != NULL)
        {
          if (! MY_ISCOFF (HEADER (ldptr).f_magic))
-           fatal_error ("%s: not a COFF file", prog_name);
+           fatal_error (input_location, "%s: not a COFF file", prog_name);
 
          if (GCC_CHECK_HDR (ldptr))
            {
@@ -2977,7 +2864,12 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
                        case SYM_AIXI:
                          if (! (filter & SCAN_CTOR))
                            break;
-                         if (is_shared && !aixlazy_flag)
+                         if (is_shared && !aixlazy_flag
+#ifdef COLLECT_EXPORT_LIST
+                             && ! static_obj
+                             && ! is_in_list (prog_name, static_libs.first)
+#endif
+                             )
                            add_to_list (&constructors, name);
                          break;
 
@@ -3051,22 +2943,25 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
                             provides an explicit export list.  */
                          if (shared_obj && !is_shared
                              && which_pass == PASS_OBJ && !export_flag)
-                           add_to_list (&exports, name);
+                           {
+                             /* Do not auto-export __dso_handle or
+                                __gcc_unwind_dbase.  They are required
+                                to be local to each module.  */
+                             if (strcmp(name, "__dso_handle") != 0
+                                 && strcmp(name, "__gcc_unwind_dbase") != 0)
+                               {
+                                 add_to_list (&exports, name);
+                               }
+                           }
 #endif
                          continue;
                        }
 
                      if (debug)
-#if !defined(EXTENDED_COFF)
                        fprintf (stderr, "\tsec=%d class=%d type=%s%o %s\n",
                                 symbol.n_scnum, symbol.n_sclass,
                                 (symbol.n_type ? "0" : ""), symbol.n_type,
                                 name);
-#else
-                       fprintf (stderr,
-                                "\tiss = %5d, value = %5ld, index = %5d, name = %s\n",
-                                symbol.iss, (long) symbol.value, symbol.index, name);
-#endif
                    }
                }
            }
@@ -3083,7 +2978,8 @@ scan_prog_file (const char *prog_name, scanpass which_pass,
        }
       else
        {
-         fatal_error ("%s: cannot open as COFF file", prog_name);
+         fatal_error (input_location, "%s: cannot open as COFF file",
+                      prog_name);
        }
 #ifdef COLLECT_EXPORT_LIST
       /* On AIX loop continues while there are more members in archive.  */
@@ -3141,7 +3037,7 @@ resolve_lib_name (const char *name)
   if (debug)
     fprintf (stderr, "not found\n");
   else
-    fatal_error ("library lib%s not found", name);
+    fatal_error (input_location, "library lib%s not found", name);
   return (NULL);
 }
 #endif /* COLLECT_EXPORT_LIST */
@@ -3193,7 +3089,8 @@ do_dsymutil (const char *output_file) {
   argv[1] = output_file;
   argv[2] = (char *) 0;
 
-  pex = collect_execute (dsymutil, real_argv, NULL, NULL, PEX_LAST | PEX_SEARCH);
+  pex = collect_execute (dsymutil, real_argv, NULL, NULL,
+                        PEX_LAST | PEX_SEARCH, false);
   do_wait (dsymutil, pex);
 }