diff gcc/collect2.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents f6334be47118
children 84e7813d76e9
line wrap: on
line diff
--- a/gcc/collect2.c	Sun Aug 21 07:07:55 2011 +0900
+++ b/gcc/collect2.c	Fri Oct 27 22:46:09 2017 +0900
@@ -1,8 +1,6 @@
 /* Collect static initialization info into data structures that can be
    traversed by C++ initialization and finalization routines.
-   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 1992-2017 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 +28,8 @@
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
+#include "filenames.h"
+#include "file-find.h"
 
 /* TARGET_64BIT may be defined to use driver specific functionality. */
 #undef TARGET_64BIT
@@ -43,6 +43,8 @@
 
 #include "collect2.h"
 #include "collect2-aix.h"
+#include "collect-utils.h"
+#include "diagnostic.h"
 #include "demangle.h"
 #include "obstack.h"
 #include "intl.h"
@@ -174,14 +176,13 @@
   int number;
 };
 
-bool vflag;				/* true if -v or --version */ 
 static int rflag;			/* true if -r */
 static int strip_flag;			/* true if -s */
-static const char *demangle_flag;
 #ifdef COLLECT_EXPORT_LIST
 static int export_flag;                 /* true if -bE */
 static int aix64_flag;			/* true if -b64 */
 static int aixrtl_flag;			/* true if -brtl */
+static int aixlazy_flag;               /* true if -blazy */
 #endif
 
 enum lto_mode_d {
@@ -191,9 +192,12 @@
 };
 
 /* Current LTO mode.  */
+#ifdef ENABLE_LTO
+static enum lto_mode_d lto_mode = LTO_MODE_WHOPR;
+#else
 static enum lto_mode_d lto_mode = LTO_MODE_NONE;
-
-bool debug;				/* true if -debug */
+#endif
+
 bool helpflag;			/* true if --help */
 
 static int shared_obj;			/* true if -shared */
@@ -215,6 +219,13 @@
 const char *c_file_name;		/* pathname of gcc */
 static char *initname, *fininame;	/* names of init and fini funcs */
 
+
+#ifdef TARGET_AIX_VERSION
+static char *aix_shared_initname;
+static char *aix_shared_fininame;       /* init/fini names as per the scheme
+					   described in config/rs6000/aix.h */
+#endif
+
 static struct head constructors;	/* list of constructors found */
 static struct head destructors;		/* list of destructors found */
 #ifdef COLLECT_EXPORT_LIST
@@ -222,8 +233,7 @@
 #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;
@@ -236,21 +246,11 @@
 static const char *target_system_root = "";
 #endif
 
-/* Structure to hold all the directories in which to search for files to
-   execute.  */
-
-struct prefix_list
-{
-  const char *prefix;         /* String to prepend to the path.  */
-  struct prefix_list *next;   /* Next in linked list.  */
-};
-
-struct path_prefix
-{
-  struct prefix_list *plist;  /* List of prefixes to try */
-  int max_len;                /* Max length of a prefix in PLIST */
-  const char *name;           /* Name of this list (used in config stuff) */
-};
+/* Whether we may unlink the output file, which should be set as soon as we
+   know we have successfully produced it.  This is typically useful to prevent
+   blindly attempting to unlink a read-only output that the target linker
+   would leave untouched.  */
+bool may_unlink_output_file = false;
 
 #ifdef COLLECT_EXPORT_LIST
 /* Lists to keep libraries to be scanned for global constructors/destructors.  */
@@ -282,26 +282,23 @@
 
 /* Special kinds of symbols that a name may denote.  */
 
-typedef enum {
+enum symkind {
   SYM_REGULAR = 0,  /* nothing special  */
 
   SYM_CTOR = 1,  /* constructor */
   SYM_DTOR = 2,  /* destructor  */
   SYM_INIT = 3,  /* shared object routine that calls all the ctors  */
   SYM_FINI = 4,  /* shared object routine that calls all the dtors  */
-  SYM_DWEH = 5   /* DWARF exception handling table  */
-} symkind;
+  SYM_DWEH = 5,  /* DWARF exception handling table  */
+  SYM_AIXI = 6,
+  SYM_AIXD = 7
+};
+
+const char tool_name[] = "collect2";
 
 static symkind is_ctor_dtor (const char *);
 
 static void handler (int);
-static char *find_a_file (struct path_prefix *, const char *);
-static void add_prefix (struct path_prefix *, const char *);
-static void prefix_from_env (const char *, struct path_prefix *);
-static void prefix_from_string (const char *, struct path_prefix *);
-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 *);
@@ -322,9 +319,6 @@
 #ifdef SCAN_LIBRARIES
 static void scan_libraries (const char *);
 #endif
-#if LINK_ELIMINATE_DUPLICATE_LDIRECTORIES
-static int is_in_args (const char *, const char **, const char **);
-#endif
 #ifdef COLLECT_EXPORT_LIST
 #if 0
 static int is_in_list (const char *, struct id *);
@@ -339,13 +333,13 @@
 /* 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.  */
 
@@ -357,6 +351,8 @@
   SCAN_INIT = 1 << SYM_INIT,
   SCAN_FINI = 1 << SYM_FINI,
   SCAN_DWEH = 1 << SYM_DWEH,
+  SCAN_AIXI = 1 << SYM_AIXI,
+  SCAN_AIXD = 1 << SYM_AIXD,
   SCAN_ALL  = ~0
 };
 
@@ -384,7 +380,7 @@
 /* Delete tempfiles and exit function.  */
 
 void
-collect_exit (int status)
+tool_cleanup (bool from_signal)
 {
   if (c_file != 0 && c_file[0])
     maybe_unlink (c_file);
@@ -402,37 +398,33 @@
 
   if (ldout != 0 && ldout[0])
     {
-      dump_file (ldout, stdout);
+      if (!from_signal)
+	dump_ld_file (ldout, stdout);
       maybe_unlink (ldout);
     }
 
   if (lderrout != 0 && lderrout[0])
     {
-      dump_file (lderrout, stderr);
+      if (!from_signal)
+	dump_ld_file (lderrout, stderr);
       maybe_unlink (lderrout);
     }
-
-  if (status != 0 && output_file != 0 && output_file[0])
-    maybe_unlink (output_file);
-
-  if (response_file)
-    maybe_unlink (response_file);
-
-  exit (status);
+}
+
+static void
+collect_atexit (void)
+{
+  tool_cleanup (false);
 }
 
-
-/* Notify user of a non-error.  */
-void
-notice (const char *cmsgid, ...)
+static void
+handler (int signo)
 {
-  va_list ap;
-
-  va_start (ap, cmsgid);
-  vfprintf (stderr, _(cmsgid), ap);
-  va_end (ap);
+  tool_cleanup (true);
+
+  signal (signo, SIG_DFL);
+  raise (signo);
 }
-
 /* Notify user of a non-error, without translating the format string.  */
 void
 notice_translated (const char *cmsgid, ...)
@@ -443,93 +435,6 @@
   vfprintf (stderr, cmsgid, ap);
   va_end (ap);
 }
-
-/* Die when sys call fails.  */
-
-void
-fatal_perror (const char * cmsgid, ...)
-{
-  int e = errno;
-  va_list ap;
-
-  va_start (ap, cmsgid);
-  fprintf (stderr, "collect2: ");
-  vfprintf (stderr, _(cmsgid), ap);
-  fprintf (stderr, ": %s\n", xstrerror (e));
-  va_end (ap);
-
-  collect_exit (FATAL_EXIT_CODE);
-}
-
-/* Just die.  */
-
-void
-fatal (const char * cmsgid, ...)
-{
-  va_list ap;
-
-  va_start (ap, cmsgid);
-  fprintf (stderr, "collect2: ");
-  vfprintf (stderr, _(cmsgid), ap);
-  fprintf (stderr, "\n");
-  va_end (ap);
-
-  collect_exit (FATAL_EXIT_CODE);
-}
-
-/* Write error message.  */
-
-void
-error (const char * gmsgid, ...)
-{
-  va_list ap;
-
-  va_start (ap, gmsgid);
-  fprintf (stderr, "collect2: ");
-  vfprintf (stderr, _(gmsgid), ap);
-  fprintf (stderr, "\n");
-  va_end(ap);
-}
-
-/* In case obstack is linked in, and abort is defined to fancy_abort,
-   provide a default entry.  */
-
-void
-fancy_abort (const char *file, int line, const char *func)
-{
-  fatal ("internal gcc abort in %s, at %s:%d", func, file, line);
-}
-
-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);
-}
-
 
 int
 file_exists (const char *name)
@@ -570,7 +475,7 @@
 }
 
 void
-dump_file (const char *name, FILE *to)
+dump_ld_file (const char *name, FILE *to)
 {
   FILE *stream = fopen (name, "r");
 
@@ -667,6 +572,10 @@
     { "GLOBAL__F_", sizeof ("GLOBAL__F_")-1, SYM_DWEH, 0 },
     { "GLOBAL__FI_", sizeof ("GLOBAL__FI_")-1, SYM_INIT, 0 },
     { "GLOBAL__FD_", sizeof ("GLOBAL__FD_")-1, SYM_FINI, 0 },
+#ifdef TARGET_AIX_VERSION
+    { "GLOBAL__AIXI_", sizeof ("GLOBAL__AIXI_")-1, SYM_AIXI, 0 },
+    { "GLOBAL__AIXD_", sizeof ("GLOBAL__AIXD_")-1, SYM_AIXD, 0 },
+#endif
     { NULL, 0, SYM_REGULAR, 0 }
   };
 
@@ -680,7 +589,7 @@
     {
       if (ch == p->name[0]
 	  && (!p->two_underscores || ((s - orig_s) >= 2))
-	  && strncmp(s, p->name, p->len) == 0)
+	  && strncmp (s, p->name, p->len) == 0)
 	{
 	  return p->ret;
 	}
@@ -705,168 +614,6 @@
 
    Return 0 if not found, otherwise return its name, allocated with malloc.  */
 
-static char *
-find_a_file (struct path_prefix *pprefix, const char *name)
-{
-  char *temp;
-  struct prefix_list *pl;
-  int len = pprefix->max_len + strlen (name) + 1;
-
-  if (debug)
-    fprintf (stderr, "Looking for '%s'\n", name);
-
-#ifdef HOST_EXECUTABLE_SUFFIX
-  len += strlen (HOST_EXECUTABLE_SUFFIX);
-#endif
-
-  temp = XNEWVEC (char, len);
-
-  /* Determine the filename to execute (special case for absolute paths).  */
-
-  if (IS_ABSOLUTE_PATH (name))
-    {
-      if (access (name, X_OK) == 0)
-	{
-	  strcpy (temp, name);
-
-	  if (debug)
-	    fprintf (stderr, "  - found: absolute path\n");
-
-	  return temp;
-	}
-
-#ifdef HOST_EXECUTABLE_SUFFIX
-	/* Some systems have a suffix for executable files.
-	   So try appending that.  */
-      strcpy (temp, name);
-	strcat (temp, HOST_EXECUTABLE_SUFFIX);
-
-	if (access (temp, X_OK) == 0)
-	  return temp;
-#endif
-
-      if (debug)
-	fprintf (stderr, "  - failed to locate using absolute path\n");
-    }
-  else
-    for (pl = pprefix->plist; pl; pl = pl->next)
-      {
-	struct stat st;
-
-	strcpy (temp, pl->prefix);
-	strcat (temp, name);
-
-	if (stat (temp, &st) >= 0
-	    && ! S_ISDIR (st.st_mode)
-	    && access (temp, X_OK) == 0)
-	  return temp;
-
-#ifdef HOST_EXECUTABLE_SUFFIX
-	/* Some systems have a suffix for executable files.
-	   So try appending that.  */
-	strcat (temp, HOST_EXECUTABLE_SUFFIX);
-
-	if (stat (temp, &st) >= 0
-	    && ! S_ISDIR (st.st_mode)
-	    && access (temp, X_OK) == 0)
-	  return temp;
-#endif
-      }
-
-  if (debug && pprefix->plist == NULL)
-    fprintf (stderr, "  - failed: no entries in prefix list\n");
-
-  free (temp);
-  return 0;
-}
-
-/* Add an entry for PREFIX to prefix list PPREFIX.  */
-
-static void
-add_prefix (struct path_prefix *pprefix, const char *prefix)
-{
-  struct prefix_list *pl, **prev;
-  int len;
-
-  if (pprefix->plist)
-    {
-      for (pl = pprefix->plist; pl->next; pl = pl->next)
-	;
-      prev = &pl->next;
-    }
-  else
-    prev = &pprefix->plist;
-
-  /* Keep track of the longest prefix.  */
-
-  len = strlen (prefix);
-  if (len > pprefix->max_len)
-    pprefix->max_len = len;
-
-  pl = XNEW (struct prefix_list);
-  pl->prefix = xstrdup (prefix);
-
-  if (*prev)
-    pl->next = *prev;
-  else
-    pl->next = (struct prefix_list *) 0;
-  *prev = pl;
-}
-
-/* Take the value of the environment variable ENV, break it into a path, and
-   add of the entries to PPREFIX.  */
-
-static void
-prefix_from_env (const char *env, struct path_prefix *pprefix)
-{
-  const char *p;
-  p = getenv (env);
-
-  if (p)
-    prefix_from_string (p, pprefix);
-}
-
-static void
-prefix_from_string (const char *p, struct path_prefix *pprefix)
-{
-  const char *startp, *endp;
-  char *nstore = XNEWVEC (char, strlen (p) + 3);
-
-  if (debug)
-    fprintf (stderr, "Convert string '%s' into prefixes, separator = '%c'\n", p, PATH_SEPARATOR);
-
-  startp = endp = p;
-  while (1)
-    {
-      if (*endp == PATH_SEPARATOR || *endp == 0)
-	{
-	  strncpy (nstore, startp, endp-startp);
-	  if (endp == startp)
-	    {
-	      strcpy (nstore, "./");
-	    }
-	  else if (! IS_DIR_SEPARATOR (endp[-1]))
-	    {
-	      nstore[endp-startp] = DIR_SEPARATOR;
-	      nstore[endp-startp+1] = 0;
-	    }
-	  else
-	    nstore[endp-startp] = 0;
-
-	  if (debug)
-	    fprintf (stderr, "  - add prefix: %s\n", nstore);
-
-	  add_prefix (pprefix, nstore);
-	  if (*endp == 0)
-	    break;
-	  endp = startp = endp + 1;
-	}
-      else
-	endp++;
-    }
-  free (nstore);
-}
-
 #ifdef OBJECT_FORMAT_NONE
 
 /* Add an entry for the object file NAME to object file list LIST.
@@ -894,7 +641,7 @@
    files contain LTO info.  The linker command line LTO_LD_ARGV
    represents the linker command that would produce a final executable
    without the use of LTO. OBJECT_LST is a vector of object file names
-   appearing in LTO_LD_ARGV that are to be considerd for link-time
+   appearing in LTO_LD_ARGV that are to be considered for link-time
    recompilation, where OBJECT is a pointer to the last valid element.
    (This awkward convention avoids an impedance mismatch with the
    usage of similarly-named variables in main().)  The elements of
@@ -952,7 +699,7 @@
       size_t num_files;
 
       if (!lto_wrapper)
-	fatal ("COLLECT_LTO_WRAPPER must be set");
+	fatal_error (input_location, "COLLECT_LTO_WRAPPER must be set");
 
       num_lto_c_args++;
 
@@ -975,7 +722,8 @@
       *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;
@@ -1013,11 +761,11 @@
       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++)
 	;
-      out_lto_ld_argv = XCNEWVEC(char *, num_files + lto_ld_argv_size + 1);
+      out_lto_ld_argv = XCNEWVEC (char *, num_files + lto_ld_argv_size + 1);
       out_lto_ld_argv_size = 0;
 
       /* After running the LTO back end, we will relink, substituting
@@ -1055,7 +803,7 @@
 
       /* 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);
+      fork_execute ("ld", out_lto_ld_argv, HAVE_GNU_LD && at_file_supplied);
       post_ld_pass (true);
       free (lto_ld_argv);
 
@@ -1065,9 +813,11 @@
     {
       /* 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);
+      fork_execute ("ld", lto_ld_argv, HAVE_GNU_LD && at_file_supplied);
       post_ld_pass (false);
     }
+  else
+    post_ld_pass (true);
 }
 
 /* Main program.  */
@@ -1075,8 +825,21 @@
 int
 main (int argc, char **argv)
 {
-  static const char *const ld_suffix	= "ld";
-  static const char *const plugin_ld_suffix = PLUGIN_LD;
+  enum linker_select
+    {
+      USE_DEFAULT_LD,
+      USE_PLUGIN_LD,
+      USE_GOLD_LD,
+      USE_BFD_LD,
+      USE_LD_MAX
+    } selected_linker = USE_DEFAULT_LD;
+  static const char *const ld_suffixes[USE_LD_MAX] =
+    {
+      "ld",
+      PLUGIN_LD_SUFFIX,
+      "ld.gold",
+      "ld.bfd"
+    };
   static const char *const real_ld_suffix = "real-ld";
   static const char *const collect_ld_suffix = "collect-ld";
   static const char *const nm_suffix	= "nm";
@@ -1087,16 +850,13 @@
   static const char *const strip_suffix = "strip";
   static const char *const gstrip_suffix = "gstrip";
 
+  const char *full_ld_suffixes[USE_LD_MAX];
 #ifdef CROSS_DIRECTORY_STRUCTURE
   /* If we look for a program in the compiler directories, we just use
      the short name, since these directories are already system-specific.
      But it we look for a program in the system directories, we need to
      qualify the program name with the target machine.  */
 
-  const char *const full_ld_suffix =
-    concat(target_machine, "-", ld_suffix, NULL);
-  const char *const full_plugin_ld_suffix =
-    concat(target_machine, "-", plugin_ld_suffix, NULL);
   const char *const full_nm_suffix =
     concat (target_machine, "-", nm_suffix, NULL);
   const char *const full_gnm_suffix =
@@ -1110,13 +870,11 @@
   const char *const full_gstrip_suffix =
     concat (target_machine, "-", gstrip_suffix, NULL);
 #else
-  const char *const full_ld_suffix	= ld_suffix;
-  const char *const full_plugin_ld_suffix = plugin_ld_suffix;
-  const char *const full_nm_suffix	= nm_suffix;
-  const char *const full_gnm_suffix	= gnm_suffix;
 #ifdef LDD_SUFFIX
   const char *const full_ldd_suffix	= ldd_suffix;
 #endif
+  const char *const full_nm_suffix	= nm_suffix;
+  const char *const full_gnm_suffix	= gnm_suffix;
   const char *const full_strip_suffix	= strip_suffix;
   const char *const full_gstrip_suffix	= gstrip_suffix;
 #endif /* CROSS_DIRECTORY_STRUCTURE */
@@ -1133,6 +891,7 @@
   char **ld1_argv;
   const char **ld1;
   bool use_plugin = false;
+  bool use_collect_ld = false;
 
   /* The kinds of symbols we will have to consider when scanning the
      outcome of a first pass link.  This is ALL to start with, then might
@@ -1146,9 +905,28 @@
   const char **ld2;
   char **object_lst;
   const char **object;
+#ifdef TARGET_AIX_VERSION
+  int object_nbr = argc;
+#endif
   int first_file;
   int num_c_args;
   char **old_argv;
+  int i;
+
+  for (i = 0; i < USE_LD_MAX; i++)
+    full_ld_suffixes[i]
+#ifdef CROSS_DIRECTORY_STRUCTURE
+      = concat (target_machine, "-", ld_suffixes[i], NULL);
+#else
+      = ld_suffixes[i];
+#endif
+
+  p = argv[0] + strlen (argv[0]);
+  while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
+    --p;
+  progname = p;
+
+  xmalloc_set_program_name (progname);
 
   old_argv = argv;
   expandargv (&argc, &argv);
@@ -1159,10 +937,12 @@
 
   num_c_args = argc + 9;
 
+#ifndef HAVE_LD_DEMANGLE
   no_demangle = !! getenv ("COLLECT_NO_DEMANGLE");
 
   /* Suppress demangling by the real linker, which may be broken.  */
-  putenv (xstrdup ("COLLECT_NO_DEMANGLE="));
+  putenv (xstrdup ("COLLECT_NO_DEMANGLE=1"));
+#endif
 
 #if defined (COLLECT2_HOST_INITIALIZATION)
   /* Perform system dependent initialization, if necessary.  */
@@ -1180,6 +960,11 @@
 
   gcc_init_libintl ();
 
+  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.  */
 
@@ -1199,7 +984,6 @@
      are called.  We also look for the -flto or -flto-partition=none flag to know
      what LTO mode we are in.  */
   {
-    int i;
     bool no_partition = false;
 
     for (i = 1; argv[i] != NULL; i ++)
@@ -1208,34 +992,42 @@
 	  debug = true;
         else if (! strcmp (argv[i], "-flto-partition=none"))
 	  no_partition = true;
-        else if ((! strncmp (argv[i], "-flto=", 6)
-		  || ! strcmp (argv[i], "-flto")) && ! use_plugin)
-	  lto_mode = LTO_MODE_WHOPR;
 	else if (!strncmp (argv[i], "-fno-lto", 8))
 	  lto_mode = LTO_MODE_NONE;
         else if (! strcmp (argv[i], "-plugin"))
 	  {
 	    use_plugin = true;
-	    lto_mode = LTO_MODE_NONE;
+	    if (selected_linker == USE_DEFAULT_LD)
+	      selected_linker = USE_PLUGIN_LD;
 	  }
+	else if (strcmp (argv[i], "-fuse-ld=bfd") == 0)
+	  selected_linker = USE_BFD_LD;
+	else if (strcmp (argv[i], "-fuse-ld=gold") == 0)
+	  selected_linker = USE_GOLD_LD;
+
 #ifdef COLLECT_EXPORT_LIST
-	/* since -brtl, -bexport, -b64 are not position dependent
-	   also check for them here */
-	if ((argv[i][0] == '-') && (argv[i][1] == 'b'))
-  	  {
-	    arg = argv[i];
-	    /* We want to disable automatic exports on AIX when user
-	       explicitly puts an export list in command line */
-	    if (arg[2] == 'E' || strncmp (&arg[2], "export", 6) == 0)
-	      export_flag = 1;
-	    else if (arg[2] == '6' && arg[3] == '4')
-	      aix64_flag = 1;
-	    else if (arg[2] == 'r' && arg[3] == 't' && arg[4] == 'l')
-	      aixrtl_flag = 1;
-	  }
+	/* These flags are position independent, although their order
+	   is important - subsequent flags override earlier ones. */
+	else if (strcmp (argv[i], "-b64") == 0)
+	    aix64_flag = 1;
+	/* -bexport:filename always needs the :filename */
+	else if (strncmp (argv[i], "-bE:", 4) == 0
+	      || strncmp (argv[i], "-bexport:", 9) == 0)
+	    export_flag = 1;
+	else if (strcmp (argv[i], "-brtl") == 0
+	      || strcmp (argv[i], "-bsvr4") == 0
+	      || strcmp (argv[i], "-G") == 0)
+	    aixrtl_flag = 1;
+	else if (strcmp (argv[i], "-bnortl") == 0)
+	    aixrtl_flag = 0;
+	else if (strcmp (argv[i], "-blazy") == 0)
+	    aixlazy_flag = 1;
 #endif
       }
-    vflag = debug;
+    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;
   }
@@ -1269,7 +1061,7 @@
   c_ptr = CONST_CAST2 (const char **, char **, c_argv);
 
   if (argc < 2)
-    fatal ("no arguments");
+    fatal_error (input_location, "no arguments");
 
 #ifdef SIGQUIT
   if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
@@ -1301,63 +1093,88 @@
   /* Maybe we know the right file to use (if not cross).  */
   ld_file_name = 0;
 #ifdef DEFAULT_LINKER
-  if (access (DEFAULT_LINKER, X_OK) == 0)
+  if (selected_linker == USE_BFD_LD || selected_linker == USE_GOLD_LD)
+    {
+      char *linker_name;
+# ifdef HOST_EXECUTABLE_SUFFIX
+      int len = (sizeof (DEFAULT_LINKER)
+		 - sizeof (HOST_EXECUTABLE_SUFFIX));
+      linker_name = NULL;
+      if (len > 0)
+	{
+	  char *default_linker = xstrdup (DEFAULT_LINKER);
+	  /* Strip HOST_EXECUTABLE_SUFFIX if DEFAULT_LINKER contains
+	     HOST_EXECUTABLE_SUFFIX.  */
+	  if (! strcmp (&default_linker[len], HOST_EXECUTABLE_SUFFIX))
+	    {
+	      default_linker[len] = '\0';
+	      linker_name = concat (default_linker,
+				    &ld_suffixes[selected_linker][2],
+				    HOST_EXECUTABLE_SUFFIX, NULL);
+	    }
+	}
+      if (linker_name == NULL)
+# endif
+      linker_name = concat (DEFAULT_LINKER,
+			    &ld_suffixes[selected_linker][2],
+			    NULL);
+      if (access (linker_name, X_OK) == 0)
+	ld_file_name = linker_name;
+    }
+  if (ld_file_name == 0 && access (DEFAULT_LINKER, X_OK) == 0)
     ld_file_name = DEFAULT_LINKER;
   if (ld_file_name == 0)
 #endif
 #ifdef REAL_LD_FILE_NAME
-  ld_file_name = find_a_file (&path, REAL_LD_FILE_NAME);
+  ld_file_name = find_a_file (&path, REAL_LD_FILE_NAME, X_OK);
   if (ld_file_name == 0)
 #endif
   /* Search the (target-specific) compiler dirs for ld'.  */
-  ld_file_name = find_a_file (&cpath, real_ld_suffix);
+  ld_file_name = find_a_file (&cpath, real_ld_suffix, X_OK);
   /* Likewise for `collect-ld'.  */
   if (ld_file_name == 0)
-    ld_file_name = find_a_file (&cpath, collect_ld_suffix);
+    {
+      ld_file_name = find_a_file (&cpath, collect_ld_suffix, X_OK);
+      use_collect_ld = ld_file_name != 0;
+    }
   /* Search the compiler directories for `ld'.  We have protection against
      recursive calls in find_a_file.  */
   if (ld_file_name == 0)
-    ld_file_name = find_a_file (&cpath,
-				use_plugin
-				? plugin_ld_suffix
-				: ld_suffix);
+    ld_file_name = find_a_file (&cpath, ld_suffixes[selected_linker], X_OK);
   /* Search the ordinary system bin directories
      for `ld' (if native linking) or `TARGET-ld' (if cross).  */
   if (ld_file_name == 0)
-    ld_file_name = find_a_file (&path,
-				use_plugin
-				? full_plugin_ld_suffix
-				: full_ld_suffix);
+    ld_file_name = find_a_file (&path, full_ld_suffixes[selected_linker], X_OK);
 
 #ifdef REAL_NM_FILE_NAME
-  nm_file_name = find_a_file (&path, REAL_NM_FILE_NAME);
+  nm_file_name = find_a_file (&path, REAL_NM_FILE_NAME, X_OK);
   if (nm_file_name == 0)
 #endif
-  nm_file_name = find_a_file (&cpath, gnm_suffix);
+  nm_file_name = find_a_file (&cpath, gnm_suffix, X_OK);
   if (nm_file_name == 0)
-    nm_file_name = find_a_file (&path, full_gnm_suffix);
+    nm_file_name = find_a_file (&path, full_gnm_suffix, X_OK);
   if (nm_file_name == 0)
-    nm_file_name = find_a_file (&cpath, nm_suffix);
+    nm_file_name = find_a_file (&cpath, nm_suffix, X_OK);
   if (nm_file_name == 0)
-    nm_file_name = find_a_file (&path, full_nm_suffix);
+    nm_file_name = find_a_file (&path, full_nm_suffix, X_OK);
 
 #ifdef LDD_SUFFIX
-  ldd_file_name = find_a_file (&cpath, ldd_suffix);
+  ldd_file_name = find_a_file (&cpath, ldd_suffix, X_OK);
   if (ldd_file_name == 0)
-    ldd_file_name = find_a_file (&path, full_ldd_suffix);
+    ldd_file_name = find_a_file (&path, full_ldd_suffix, X_OK);
 #endif
 
 #ifdef REAL_STRIP_FILE_NAME
-  strip_file_name = find_a_file (&path, REAL_STRIP_FILE_NAME);
+  strip_file_name = find_a_file (&path, REAL_STRIP_FILE_NAME, X_OK);
   if (strip_file_name == 0)
 #endif
-  strip_file_name = find_a_file (&cpath, gstrip_suffix);
+  strip_file_name = find_a_file (&cpath, gstrip_suffix, X_OK);
   if (strip_file_name == 0)
-    strip_file_name = find_a_file (&path, full_gstrip_suffix);
+    strip_file_name = find_a_file (&path, full_gstrip_suffix, X_OK);
   if (strip_file_name == 0)
-    strip_file_name = find_a_file (&cpath, strip_suffix);
+    strip_file_name = find_a_file (&cpath, strip_suffix, X_OK);
   if (strip_file_name == 0)
-    strip_file_name = find_a_file (&path, full_strip_suffix);
+    strip_file_name = find_a_file (&path, full_strip_suffix, X_OK);
 
   /* Determine the full path name of the C compiler to use.  */
   c_file_name = getenv ("COLLECT_GCC");
@@ -1370,12 +1187,12 @@
 #endif
     }
 
-  p = find_a_file (&cpath, c_file_name);
+  p = find_a_file (&cpath, c_file_name, X_OK);
 
   /* Here it should be safe to use the system search path since we should have
      already qualified the name of the compiler when it is needed.  */
   if (p == 0)
-    p = find_a_file (&path, c_file_name);
+    p = find_a_file (&path, c_file_name, X_OK);
 
   if (p)
     c_file_name = p;
@@ -1388,8 +1205,11 @@
 #ifdef COLLECT_EXPORT_LIST
   export_file = make_temp_file (".x");
 #endif
-  ldout = make_temp_file (".ld");
-  lderrout = make_temp_file (".le");
+  if (!debug)
+    {
+      ldout = make_temp_file (".ld");
+      lderrout = make_temp_file (".le");
+    }
   *c_ptr++ = c_file_name;
   *c_ptr++ = "-x";
   *c_ptr++ = "c";
@@ -1450,12 +1270,6 @@
   /* After the first file, put in the c++ rt0.  */
 
   first_file = 1;
-#ifdef HAVE_LD_DEMANGLE
-  if (!demangle_flag && !no_demangle)
-    demangle_flag = "--demangle";
-  if (demangle_flag)
-    *ld1++ = *ld2++ = demangle_flag;
-#endif
   while ((arg = *++argv) != (char *) 0)
     {
       *ld1++ = *ld2++ = arg;
@@ -1490,6 +1304,74 @@
 			 "configuration");
 #endif
 		}
+	      else if (!use_collect_ld
+		       && strncmp (arg, "-fuse-ld=", 9) == 0)
+		{
+		  /* Do not pass -fuse-ld={bfd|gold} to the linker. */
+		  ld1--;
+		  ld2--;
+		}
+	      else if (strncmp (arg, "-fno-lto", 8) == 0)
+		{
+		  /* Do not pass -fno-lto to the linker. */
+		  ld1--;
+		  ld2--;
+		}
+#ifdef TARGET_AIX_VERSION
+	      else
+		{
+		  /* File containing a list of input files to process.  */
+
+		  FILE *stream;
+                  char buf[MAXPATHLEN + 2];
+		  /* Number of additionnal object files.  */
+		  int add_nbr = 0;
+		  /* Maximum of additionnal object files before vector
+		     expansion.  */
+		  int add_max = 0;
+		  const char *list_filename = arg + 2;
+
+		  /* Accept -fFILENAME and -f FILENAME.  */
+		  if (*list_filename == '\0' && argv[1])
+		    {
+		      ++argv;
+		      list_filename = *argv;
+		      *ld1++ = *ld2++ = *argv;
+		    }
+
+		  stream = fopen (list_filename, "r");
+		  if (stream == NULL)
+		    fatal_error (input_location, "can't open %s: %m",
+				 list_filename);
+
+		  while (fgets (buf, sizeof buf, stream) != NULL)
+		    {
+		      /* Remove end of line.  */
+		      int len = strlen (buf);
+		      if (len >= 1 && buf[len - 1] =='\n')
+			buf[len - 1] = '\0';
+
+		      /* Put on object vector.
+			 Note: we only expanse vector here, so we must keep
+			 extra space for remaining arguments.  */
+		      if (add_nbr >= add_max)
+			{
+			  int pos =
+			    object - CONST_CAST2 (const char **, char **,
+						  object_lst);
+			  add_max = (add_max == 0) ? 16 : add_max * 2;
+			  object_lst = XRESIZEVEC (char *, object_lst,
+                                                   object_nbr + add_max);
+			  object = CONST_CAST2 (const char **, char **,
+						object_lst) + pos;
+			  object_nbr += add_max;
+			}
+		      *object++ = xstrdup (buf);
+		      add_nbr++;
+		    }
+		  fclose (stream);
+		}
+#endif
               break;
 
 	    case 'l':
@@ -1517,15 +1399,6 @@
 	    case 'L':
 	      add_prefix (&cmdline_lib_dirs, arg+2);
 	      break;
-#else
-#if LINK_ELIMINATE_DUPLICATE_LDIRECTORIES
-	    case 'L':
-	      if (is_in_args (arg,
-			      CONST_CAST2 (const char **, char **, ld1_argv),
-			      ld1 - 1))
-		--ld1;
-	      break;
-#endif /* LINK_ELIMINATE_DUPLICATE_LDIRECTORIES */
 #endif
 
 	    case 'o':
@@ -1553,22 +1426,22 @@
 
 	    case 'v':
 	      if (arg[2] == '\0')
-		vflag = true;
+		verbose = true;
 	      break;
 
 	    case '-':
 	      if (strcmp (arg, "--no-demangle") == 0)
 		{
-		  demangle_flag = arg;
+#ifndef HAVE_LD_DEMANGLE
 		  no_demangle = 1;
 		  ld1--;
 		  ld2--;
+#endif
 		}
 	      else if (strncmp (arg, "--demangle", 10) == 0)
 		{
-		  demangle_flag = arg;
+#ifndef HAVE_LD_DEMANGLE
 		  no_demangle = 0;
-#ifndef HAVE_LD_DEMANGLE
 		  if (arg[10] == '=')
 		    {
 		      enum demangling_styles style
@@ -1578,14 +1451,14 @@
 		      else
 			current_demangling_style = style;
 		    }
-#endif
 		  ld1--;
 		  ld2--;
+#endif
 		}
 	      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;
@@ -1670,24 +1543,18 @@
 
       exportf = fopen (export_file, "w");
       if (exportf == (FILE *) 0)
-	fatal_perror ("fopen %s", export_file);
+	fatal_error (input_location, "fopen %s: %m", export_file);
       write_aix_file (exportf, exports.first);
       if (fclose (exportf))
-	fatal_perror ("fclose %s", export_file);
+	fatal_error (input_location, "fclose %s: %m", export_file);
     }
 #endif
 
   *c_ptr++ = c_file;
   *c_ptr = *ld1 = *object = (char *) 0;
 
-  if (vflag)
-    {
-      notice ("collect2 version %s", version_string);
-#ifdef TARGET_VERSION
-      TARGET_VERSION;
-#endif
-      fprintf (stderr, "\n");
-    }
+  if (verbose)
+    notice ("collect2 version %s\n", version_string);
 
   if (helpflag)
     {
@@ -1802,9 +1669,9 @@
                                    "%d destructors found\n",
                                    destructors.number),
                          destructors.number);
-      notice_translated (ngettext("%d frame table found\n",
-                                  "%d frame tables found\n",
-                                  frame_tables.number),
+      notice_translated (ngettext ("%d frame table found\n",
+                                   "%d frame tables found\n",
+				   frame_tables.number),
                          frame_tables.number);
     }
 
@@ -1839,7 +1706,7 @@
 	  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
@@ -1856,15 +1723,15 @@
   sort_ids (&constructors);
   sort_ids (&destructors);
 
-  maybe_unlink(output_file);
+  maybe_unlink (output_file);
   outf = fopen (c_file, "w");
   if (outf == (FILE *) 0)
-    fatal_perror ("fopen %s", c_file);
+    fatal_error (input_location, "fopen %s: %m", c_file);
 
   write_c_file (outf, c_file);
 
   if (fclose (outf))
-    fatal_perror ("fclose %s", 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
@@ -1886,6 +1753,11 @@
       if (! exports.first)
 	*ld2++ = concat ("-bE:", export_file, NULL);
 
+#ifdef TARGET_AIX_VERSION
+      add_to_list (&exports, aix_shared_initname);
+      add_to_list (&exports, aix_shared_fininame);
+#endif
+
 #ifndef LD_INIT_SWITCH
       add_to_list (&exports, initname);
       add_to_list (&exports, fininame);
@@ -1894,10 +1766,10 @@
 #endif
       exportf = fopen (export_file, "w");
       if (exportf == (FILE *) 0)
-	fatal_perror ("fopen %s", export_file);
+	fatal_error (input_location, "fopen %s: %m", export_file);
       write_aix_file (exportf, exports.first);
       if (fclose (exportf))
-	fatal_perror ("fclose %s", export_file);
+	fatal_error (input_location, "fclose %s: %m", export_file);
     }
 #endif
 
@@ -1920,7 +1792,7 @@
   /* 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);
@@ -1933,7 +1805,7 @@
     maybe_run_lto_and_relink (ld2_argv, object_lst, object, true);
   else
     {
-      fork_execute ("ld", ld2_argv);
+      fork_execute ("ld", ld2_argv, HAVE_GNU_LD && at_file_supplied);
       post_ld_pass (false);
     }
 
@@ -1953,169 +1825,22 @@
 }
 
 
-/* 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_perror ("can't get program status");
-  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" : "");
-	  collect_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);
-      collect_exit (ret);
-    }
-
-  if (response_file)
-    {
-      unlink (response_file);
-      response_file = NULL;
-    }
-}
-
-
-/* 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 ("could not open response file %s", response_file);
-
-      status = writeargv (current_argv, f);
-
-      if (status)
-        fatal ("could not write to response file %s", response_file);
-
-      status = fclose (f);
-
-      if (EOF == status)
-        fatal ("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 ("cannot find '%s'", prog);
-
-  pex = pex_init (0, "collect2", NULL);
-  if (pex == NULL)
-    fatal_perror ("pex_init failed");
-
-  errmsg = pex_run (pex, flags, argv[0], argv, outname,
-		    errname, &err);
-  if (errmsg != NULL)
-    {
-      if (err != 0)
-	{
-	  errno = err;
-	  fatal_perror (errmsg);
-	}
-      else
-	fatal (errmsg);
-    }
-
-  if (response_arg)
-    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);
-}
-
-/* Unlink a file unless we are debugging.  */
-
-static void
+/* Unlink FILE unless we are debugging or this is the output_file
+   and we may not unlink it.  */
+
+void
 maybe_unlink (const char *file)
 {
-  if (!debug)
-    unlink_if_ordinary (file);
-  else
-    notice ("[Leaving %s]\n", file);
+  if (debug)
+    {
+      notice ("[Leaving %s]\n", file);
+      return;
+    }
+
+  if (file == output_file && !may_unlink_output_file)
+    return;
+
+  unlink_if_ordinary (file);
 }
 
 /* Call maybe_unlink on the NULL-terminated list, FILE_LIST.  */
@@ -2172,6 +1897,19 @@
 {
   int pos = 0, pri;
 
+#ifdef TARGET_AIX_VERSION
+  /* Run dependent module initializers before any constructors in this
+     module.  */
+  switch (is_ctor_dtor (name))
+    {
+    case SYM_AIXI:
+    case SYM_AIXD:
+      return INT_MIN;
+    default:
+      break;
+    }
+#endif
+
   while (name[pos] == '_')
     ++pos;
   pos += 10; /* strlen ("GLOBAL__X_") */
@@ -2235,22 +1973,6 @@
     }
 }
 
-#if LINK_ELIMINATE_DUPLICATE_LDIRECTORIES
-/* Given a STRING, return nonzero if it occurs in the list in range
-   [ARGS_BEGIN,ARGS_END).  */
-
-static int
-is_in_args (const char *string, const char **args_begin,
-	    const char **args_end)
-{
-  const char **args_pointer;
-  for (args_pointer = args_begin; args_pointer != args_end; ++args_pointer)
-    if (strcmp (string, *args_pointer) == 0)
-      return 1;
-  return 0;
-}
-#endif /* LINK_ELIMINATE_DUPLICATE_LDIRECTORIES */
-
 #ifdef COLLECT_EXPORT_LIST
 /* This function is really used only on AIX, but may be useful.  */
 #if 0
@@ -2314,12 +2036,8 @@
   int frames = (frame_tables.number > 0);
 
   /* Figure out name of output_file, stripping off .so version.  */
-  p = strrchr (output_file, '/');
-  if (p == 0)
-    p = output_file;
-  else
-    p++;
-  q = p;
+  q = p = lbasename (output_file);
+
   while (q)
     {
       q = strchr (q,'.');
@@ -2330,7 +2048,7 @@
 	}
       else
 	{
-	  if (strncmp (q, SHLIB_SUFFIX, strlen (SHLIB_SUFFIX)) == 0)
+	  if (filename_ncmp (q, SHLIB_SUFFIX, strlen (SHLIB_SUFFIX)) == 0)
 	    {
 	      q += strlen (SHLIB_SUFFIX);
 	      break;
@@ -2352,11 +2070,22 @@
 
   initname = concat ("_GLOBAL__FI_", prefix, NULL);
   fininame = concat ("_GLOBAL__FD_", prefix, NULL);
+#ifdef TARGET_AIX_VERSION
+  aix_shared_initname = concat ("_GLOBAL__AIXI_", prefix, NULL);
+  aix_shared_fininame = concat ("_GLOBAL__AIXD_", prefix, NULL);
+#endif
 
   free (prefix);
 
   /* Write the tables as C code.  */
 
+  /* This count variable is used to prevent multiple calls to the
+     constructors/destructors.
+     This guard against multiple calls is important on AIX as the initfini
+     functions are deliberately invoked multiple times as part of the
+     mechanisms GCC uses to order constructors across different dependent
+     shared libraries (see config/rs6000/aix.h).
+   */
   fprintf (stream, "static int count;\n");
   fprintf (stream, "typedef void entry_pt();\n");
   write_list_with_asm (stream, "extern entry_pt ", constructors.first);
@@ -2379,12 +2108,23 @@
       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");
@@ -2427,8 +2167,8 @@
 
   if (shared_obj)
     {
-      COLLECT_SHARED_INIT_FUNC(stream, initname);
-      COLLECT_SHARED_FINI_FUNC(stream, fininame);
+      COLLECT_SHARED_INIT_FUNC (stream, initname);
+      COLLECT_SHARED_FINI_FUNC (stream, fininame);
     }
 }
 
@@ -2586,13 +2326,13 @@
 
   /* LTO objects must be in a known format.  This check prevents
      us from accepting an archive containing LTO objects, which
-     gcc cannnot currently handle.  */
+     gcc cannot currently handle.  */
   if (which_pass == PASS_LTOINFO && !maybe_lto_object_file (prog_name))
     return;
 
   /* If we do not have an `nm', complain.  */
   if (nm_file_name == 0)
-    fatal ("cannot find 'nm'");
+    fatal_error (input_location, "cannot find 'nm'");
 
   nm_argv[argc++] = nm_file_name;
   if (NM_FLAGS[0] != '\0')
@@ -2602,7 +2342,7 @@
   nm_argv[argc++] = (char *) 0;
 
   /* Trace if needed.  */
-  if (vflag)
+  if (verbose)
     {
       const char **p_argv;
       const char *str;
@@ -2618,7 +2358,7 @@
 
   pex = pex_init (PEX_USE_PIPES, "collect2", NULL);
   if (pex == NULL)
-    fatal_perror ("pex_init failed");
+    fatal_error (input_location, "pex_init failed: %m");
 
   errmsg = pex_run (pex, 0, nm_file_name, real_nm_argv, NULL, HOST_BIT_BUCKET,
 		    &err);
@@ -2627,10 +2367,10 @@
       if (err != 0)
 	{
 	  errno = err;
-	  fatal_perror (errmsg);
+	  fatal_error (input_location, "%s: %m", _(errmsg));
 	}
       else
-	fatal (errmsg);
+	fatal_error (input_location, errmsg);
     }
 
   int_handler  = (void (*) (int)) signal (SIGINT,  SIG_IGN);
@@ -2640,7 +2380,7 @@
 
   inf = pex_read_output (pex, 0);
   if (inf == NULL)
-    fatal_perror ("can't open nm output");
+    fatal_error (input_location, "can't open nm output: %m");
 
   if (debug)
     {
@@ -2703,6 +2443,7 @@
 
 
       *end = '\0';
+
       switch (is_ctor_dtor (name))
 	{
 	case SYM_CTOR:
@@ -2723,7 +2464,8 @@
 	  if (! (filter & SCAN_INIT))
 	    break;
 	  if (which_pass != PASS_LIB)
-	    fatal ("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
@@ -2733,7 +2475,8 @@
 	  if (! (filter & SCAN_FINI))
 	    break;
 	  if (which_pass != PASS_LIB)
-	    fatal ("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
@@ -2798,7 +2541,7 @@
   ldd_argv[argc++] = (char *) 0;
 
   /* Trace if needed.  */
-  if (vflag)
+  if (verbose)
     {
       const char **p_argv;
       const char *str;
@@ -2814,7 +2557,7 @@
 
   pex = pex_init (PEX_USE_PIPES, "collect2", NULL);
   if (pex == NULL)
-    fatal_perror ("pex_init failed");
+    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)
@@ -2822,10 +2565,10 @@
       if (err != 0)
 	{
 	  errno = err;
-	  fatal_perror (errmsg);
+	  fatal_error (input_location, "%s: %m", _(errmsg));
 	}
       else
-	fatal (errmsg);
+	fatal_error (input_location, errmsg);
     }
 
   int_handler  = (void (*) (int)) signal (SIGINT,  SIG_IGN);
@@ -2835,7 +2578,7 @@
 
   inf = pex_read_output (pex, 0);
   if (inf == NULL)
-    fatal_perror ("can't open ldd output");
+    fatal_error (input_location, "can't open ldd output: %m");
 
   if (debug)
     notice ("\nldd output with constructors/destructors.\n");
@@ -2853,7 +2596,7 @@
 
       name = p;
       if (strncmp (name, "not found", sizeof ("not found") - 1) == 0)
-	fatal ("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;
@@ -2865,7 +2608,8 @@
       if (access (name, R_OK) == 0)
 	add_to_list (&libraries, name);
       else
-	fatal ("unable to open dynamic dependency '%s'", buf);
+	fatal_error (input_location, "unable to open dynamic dependency '%s'",
+		     buf);
 
       if (debug)
 	fprintf (stderr, "\t%s\n", buf);
@@ -2899,16 +2643,16 @@
 
 #if defined (EXTENDED_COFF)
 
-#   define GCC_SYMBOLS(X)	(SYMHEADER(X).isymMax + SYMHEADER(X).iextMax)
+#   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)
+#   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_SYMBOLS(X)	(HEADER (ldptr).f_nsyms)
 #   define GCC_SYMENT		SYMENT
 #   if defined (C_WEAKEXT)
 #     define GCC_OK_SYMBOL(X) \
@@ -2936,12 +2680,14 @@
 /* 0757 = U803XTOCMAGIC (AIX 4.3) and 0767 = U64_TOCMAGIC (AIX V5) */
 #if TARGET_AIX_VERSION >= 51
 #   define GCC_CHECK_HDR(X) \
-     ((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \
-      || (HEADER (X).f_magic == 0767 && aix64_flag))
+     (((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \
+       || (HEADER (X).f_magic == 0767 && aix64_flag)) \
+      && !(HEADER (X).f_flags & F_LOADONLY))
 #else
 #   define GCC_CHECK_HDR(X) \
-     ((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \
-      || (HEADER (X).f_magic == 0757 && aix64_flag))
+     (((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \
+       || (HEADER (X).f_magic == 0757 && aix64_flag)) \
+      && !(HEADER (X).f_flags & F_LOADONLY))
 #endif
 
 #endif
@@ -3026,7 +2772,7 @@
       if ((ldptr = ldopen (CONST_CAST (char *, prog_name), ldptr)) != NULL)
 	{
 	  if (! MY_ISCOFF (HEADER (ldptr).f_magic))
-	    fatal ("%s: not a COFF file", prog_name);
+	    fatal_error (input_location, "%s: not a COFF file", prog_name);
 
 	  if (GCC_CHECK_HDR (ldptr))
 	    {
@@ -3062,6 +2808,25 @@
 
 		      switch (is_ctor_dtor (name))
 			{
+#if TARGET_AIX_VERSION
+		      /* Add AIX shared library initalisers/finalisers
+			 to the constructors/destructors list of the
+			 current module.  */
+			case SYM_AIXI:
+			  if (! (filter & SCAN_CTOR))
+			    break;
+			  if (is_shared && !aixlazy_flag)
+			    add_to_list (&constructors, name);
+			  break;
+
+			case SYM_AIXD:
+			  if (! (filter & SCAN_DTOR))
+			    break;
+			  if (is_shared && !aixlazy_flag)
+			    add_to_list (&destructors, name);
+			  break;
+#endif
+
 			case SYM_CTOR:
 			  if (! (filter & SCAN_CTOR))
 			    break;
@@ -3124,7 +2889,16 @@
 			     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;
 			}
@@ -3156,7 +2930,8 @@
 	}
       else
 	{
-	  fatal ("%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.  */
@@ -3164,7 +2939,7 @@
   while (ldclose (ldptr) == FAILURE);
 #else
   /* Otherwise we simply close ldptr.  */
-  (void) ldclose(ldptr);
+  (void) ldclose (ldptr);
 #endif
 }
 #endif /* OBJECT_FORMAT_COFF */
@@ -3184,7 +2959,7 @@
     if (libpaths[i]->max_len > l)
       l = libpaths[i]->max_len;
 
-  lib_buf = XNEWVEC (char, l + strlen(name) + 10);
+  lib_buf = XNEWVEC (char, l + strlen (name) + 10);
 
   for (i = 0; libpaths[i]; i++)
     {
@@ -3192,10 +2967,10 @@
       for (; list; list = list->next)
 	{
 	  /* The following lines are needed because path_prefix list
-	     may contain directories both with trailing '/' and
+	     may contain directories both with trailing DIR_SEPARATOR and
 	     without it.  */
 	  const char *p = "";
-	  if (list->prefix[strlen(list->prefix)-1] != '/')
+	  if (!IS_DIR_SEPARATOR (list->prefix[strlen (list->prefix)-1]))
 	    p = "/";
 	  for (j = 0; j < 2; j++)
 	    {
@@ -3214,7 +2989,7 @@
   if (debug)
     fprintf (stderr, "not found\n");
   else
-    fatal ("library lib%s not found", name);
+    fatal_error (input_location, "library lib%s not found", name);
   return (NULL);
 }
 #endif /* COLLECT_EXPORT_LIST */
@@ -3266,7 +3041,8 @@
   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);
 }