refactor SLP constant insertion and provde entry insert helper
[gcc.git] / gcc / collect2.c
index 9c3a1c557276d6fbdc2097987a21efdaf10710ca..f8a5ce45994eb628f6f8efd8fb72e5100bc0c130 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-2020 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
@@ -201,6 +203,7 @@ static enum lto_mode_d lto_mode = LTO_MODE_NONE;
 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.  */
@@ -208,8 +211,6 @@ static const char *o_file;          /* <xxx>.o for constructor/destructor list.  */
 static const char *export_file;                /* <xxx>.x for AIX export list.  */
 #endif
 static char **lto_o_files;             /* Output files for LTO.  */
-const char *ldout;                     /* File for ld stdout.  */
-const char *lderrout;                  /* File for ld stderr.  */
 static const char *output_file;                /* Output file for ld.  */
 static const char *nm_file_name;       /* pathname of nm */
 #ifdef LDD_SUFFIX
@@ -255,6 +256,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,
@@ -282,7 +284,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 */
@@ -292,7 +294,7 @@ typedef enum {
   SYM_DWEH = 5,  /* DWARF exception handling table  */
   SYM_AIXI = 6,
   SYM_AIXD = 7
-} symkind;
+};
 
 const char tool_name[] = "collect2";
 
@@ -320,9 +322,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
@@ -333,13 +333,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,6 +382,10 @@ static void scan_prog_file (const char *, scanpass, scanfilter);
 void
 tool_cleanup (bool from_signal)
 {
+  /* maybe_unlink may call notice, which is not signal safe.  */
+  if (from_signal)
+    verbose = false;
+
   if (c_file != 0 && c_file[0])
     maybe_unlink (c_file);
 
@@ -395,20 +399,6 @@ tool_cleanup (bool from_signal)
 
   if (lto_o_files)
     maybe_unlink_list (lto_o_files);
-
-  if (ldout != 0 && ldout[0])
-    {
-      if (!from_signal)
-       dump_ld_file (ldout, stdout);
-      maybe_unlink (ldout);
-    }
-
-  if (lderrout != 0 && lderrout[0])
-    {
-      if (!from_signal)
-       dump_ld_file (lderrout, stderr);
-      maybe_unlink (lderrout);
-    }
 }
 
 static void
@@ -474,77 +464,6 @@ extract_string (const char **pp)
   return XOBFINISH (&temporary_obstack, char *);
 }
 \f
-void
-dump_ld_file (const char *name, FILE *to)
-{
-  FILE *stream = fopen (name, "r");
-
-  if (stream == 0)
-    return;
-  while (1)
-    {
-      int c;
-      while (c = getc (stream),
-            c != EOF && (ISIDNUM (c) || c == '$' || c == '.'))
-       obstack_1grow (&temporary_obstack, c);
-      if (obstack_object_size (&temporary_obstack) > 0)
-       {
-         const char *word, *p;
-         char *result;
-         obstack_1grow (&temporary_obstack, '\0');
-         word = XOBFINISH (&temporary_obstack, const char *);
-
-         if (*word == '.')
-           ++word, putc ('.', to);
-         p = word;
-         if (!strncmp (p, USER_LABEL_PREFIX, strlen (USER_LABEL_PREFIX)))
-           p += strlen (USER_LABEL_PREFIX);
-
-#ifdef HAVE_LD_DEMANGLE
-         result = 0;
-#else
-         if (no_demangle)
-           result = 0;
-         else
-           result = cplus_demangle (p, DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE);
-#endif
-
-         if (result)
-           {
-             int diff;
-             fputs (result, to);
-
-             diff = strlen (word) - strlen (result);
-             while (diff > 0 && c == ' ')
-               --diff, putc (' ', to);
-             if (diff < 0 && c == ' ')
-               {
-                 while (diff < 0 && c == ' ')
-                   ++diff, c = getc (stream);
-                 if (!ISSPACE (c))
-                   {
-                     /* Make sure we output at least one space, or
-                        the demangled symbol name will run into
-                        whatever text follows.  */
-                     putc (' ', to);
-                   }
-               }
-
-             free (result);
-           }
-         else
-           fputs (word, to);
-
-         fflush (to);
-         obstack_free (&temporary_obstack, temporary_firstobj);
-       }
-      if (c == EOF)
-       break;
-      putc (c, to);
-    }
-  fclose (stream);
-}
-\f
 /* Return the kind of symbol denoted by name S.  */
 
 static symkind
@@ -699,7 +618,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++;
 
@@ -741,7 +661,10 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst,
              ++num_files;
          }
 
-       lto_o_files = XNEWVEC (char *, num_files + 1);
+       /* signal handler may access uninitialized memory
+          and delete whatever it points to, if lto_o_files
+          is not allocated with calloc.  */
+       lto_o_files = XCNEWVEC (char *, num_files + 1);
        lto_o_files[num_files] = NULL;
        start = XOBFINISH (&temporary_obstack, char *);
        for (i = 0; i < num_files; ++i)
@@ -761,7 +684,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++)
        ;
@@ -804,7 +727,9 @@ 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, HAVE_GNU_LD && at_file_supplied);
-      post_ld_pass (true);
+      /* 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);
@@ -814,10 +739,35 @@ 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, HAVE_GNU_LD && at_file_supplied);
-      post_ld_pass (false);
+      /* No LTO objects were found, so no new temp file.  */
+      post_ld_pass (/*temp_file*/false);
     }
   else
-    post_ld_pass (true);
+    post_ld_pass (false); /* No LTO objects were found, no temp file.  */
+}
+/* Entry point for linker invoation.  Called from main in collect2.c.
+   LD_ARGV is an array of arguments for the linker.  */
+
+static void
+do_link (char **ld_argv)
+{
+  struct pex_obj *pex;
+  const char *prog = "ld";
+  pex = collect_execute (prog, ld_argv, NULL, NULL,
+                        PEX_LAST | PEX_SEARCH,
+                        HAVE_GNU_LD && at_file_supplied);
+  int ret = collect_wait (prog, pex);
+  if (ret)
+    {
+      error ("ld returned %d exit status", ret);
+      exit (ret);
+    }
+  else
+    {
+      /* We have just successfully produced an output file, so assume that we
+        may unlink it if need be for now on.  */
+      may_unlink_output_file = true;
+    }
 }
 \f
 /* Main program.  */
@@ -831,6 +781,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] =
@@ -838,7 +789,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";
@@ -911,6 +863,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++)
@@ -963,7 +918,7 @@ main (int argc, char **argv)
   diagnostic_initialize (global_dc, 0);
 
   if (atexit (collect_atexit) != 0)
-    fatal_error ("atexit failed");
+    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.  */
@@ -976,13 +931,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;
 
@@ -990,8 +953,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"))
@@ -1004,6 +965,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
@@ -1024,34 +996,41 @@ main (int argc, char **argv)
            aixlazy_flag = 1;
 #endif
       }
-    verbose = 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 */
@@ -1061,7 +1040,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)
@@ -1093,7 +1072,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
@@ -1200,16 +1180,23 @@ 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 = concat (output_file, ".cdtor.c", NULL);
+      o_file = concat (output_file, ".cdtor.o", NULL);
 #ifdef COLLECT_EXPORT_LIST
-  export_file = make_temp_file (".x");
+      export_file = concat (output_file, ".x", NULL);
 #endif
-  if (!debug)
+    }
+  else
     {
-      ldout = make_temp_file (".ld");
-      lderrout = make_temp_file (".le");
+      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
     }
+  /* Build the command line to compile the ctor/dtor list.  */
   *c_ptr++ = c_file_name;
   *c_ptr++ = "-x";
   *c_ptr++ = "c";
@@ -1241,6 +1228,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);
@@ -1269,6 +1258,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)
     {
@@ -1307,7 +1299,7 @@ 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--;
                }
@@ -1341,7 +1333,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)
                    {
@@ -1373,6 +1366,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)
                {
@@ -1389,6 +1394,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;
@@ -1446,7 +1453,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;
                    }
@@ -1489,6 +1496,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
        }
@@ -1500,6 +1509,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
@@ -1524,9 +1535,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);
 
@@ -1542,10 +1555,10 @@ 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
 
@@ -1564,7 +1577,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");
     }
@@ -1627,7 +1640,7 @@ main (int argc, char **argv)
        functions from precise cross reference insertions by the compiler.  */
 
     if (early_exit || ld1_filter != SCAN_NOTHING)
-      do_tlink (ld1_argv, object_lst);
+      do_link (ld1_argv);
 
     if (early_exit)
       {
@@ -1639,10 +1652,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;
       }
   }
@@ -1687,10 +1698,10 @@ main (int argc, char **argv)
 #endif
       )
     {
-      /* Do tlink without additional code generation now if we didn't
+      /* Do link without additional code generation now if we didn't
         do it earlier for scanning purposes.  */
       if (ld1_filter == SCAN_NOTHING)
-       do_tlink (ld1_argv, object_lst);
+       do_link (ld1_argv);
 
       if (lto_mode)
         maybe_run_lto_and_relink (ld1_argv, object_lst, object, false);
@@ -1711,10 +1722,7 @@ main (int argc, char **argv)
 #ifdef COLLECT_EXPORT_LIST
       maybe_unlink (export_file);
 #endif
-      post_ld_pass (false);
-
-      maybe_unlink (c_file);
-      maybe_unlink (o_file);
+      post_ld_pass (/*temp_file*/false);
       return 0;
     }
 
@@ -1725,12 +1733,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
@@ -1765,10 +1773,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
 
@@ -1793,19 +1801,19 @@ main (int argc, char **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);
+  /* On AIX we must call link because of possible templates resolution.  */
+  do_link (ld2_argv);
 
   if (lto_mode)
     maybe_run_lto_and_relink (ld2_argv, object_lst, object, false);
 #else
-  /* Otherwise, simply call ld because tlink is already done.  */
+  /* Otherwise, simply call ld because link is already done.  */
   if (lto_mode)
     maybe_run_lto_and_relink (ld2_argv, object_lst, object, true);
   else
     {
       fork_execute ("ld", ld2_argv, HAVE_GNU_LD && at_file_supplied);
-      post_ld_pass (false);
+      post_ld_pass (/*temp_file*/false);
     }
 
   /* Let scan_prog_file do any final mods (OSF/rose needs this for
@@ -1813,13 +1821,6 @@ main (int argc, char **argv)
   scan_prog_file (output_file, PASS_SECOND, SCAN_ALL);
 #endif
 
-  maybe_unlink (c_file);
-  maybe_unlink (o_file);
-
-#ifdef COLLECT_EXPORT_LIST
-  maybe_unlink (export_file);
-#endif
-
   return 0;
 }
 
@@ -1830,9 +1831,10 @@ main (int argc, char **argv)
 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;
     }
 
@@ -1974,7 +1976,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)
 {
@@ -1985,7 +1986,6 @@ is_in_list (const char *prefix, struct id *list)
     }
     return 0;
 }
-#endif
 #endif /* COLLECT_EXPORT_LIST */
 
 /* Added for debugging purpose.  */
@@ -2107,12 +2107,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");
@@ -2253,38 +2264,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;
 }
 
@@ -2307,7 +2332,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;
@@ -2315,12 +2339,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')
@@ -2346,7 +2375,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);
@@ -2355,10 +2384,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);
@@ -2368,15 +2397,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)
@@ -2387,30 +2411,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.  */
@@ -2452,7 +2452,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
@@ -2462,7 +2463,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
@@ -2518,7 +2520,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;
     }
 
@@ -2543,7 +2545,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)
@@ -2551,10 +2553,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);
@@ -2564,7 +2566,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");
@@ -2582,7 +2584,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;
@@ -2594,7 +2596,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);
@@ -2626,17 +2629,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)
@@ -2675,8 +2667,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.  */
@@ -2757,7 +2747,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))
            {
@@ -2800,7 +2790,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;
 
@@ -2874,22 +2869,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
                    }
                }
            }
@@ -2906,7 +2904,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.  */
@@ -2964,7 +2963,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 */