OSDN Git Service

2007-11-27 H.J. Lu <hongjiu.lu@intel.com>
[pf3gnuchains/gcc-fork.git] / gcc / collect2.c
index 2d49cce..a673f25 100644 (file)
@@ -1,7 +1,7 @@
 /* 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 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007 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).
@@ -10,7 +10,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -19,9 +19,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 
 /* Build tables of static constructors and destructors and run ld.  */
@@ -35,19 +34,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #  define SIGCHLD SIGCLD
 #endif
 
-#ifdef vfork /* Autoconf may define this to fork for us.  */
-# define VFORK_STRING "fork"
-#else
-# define VFORK_STRING "vfork"
-#endif
-#ifdef HAVE_VFORK_H
-#include <vfork.h>
-#endif
-#ifdef VMS
-#define vfork() (decc$$alloc_vfork_blocks() >= 0 ? \
-               lib$get_current_invo_context(decc$$get_vfork_jmpbuf()) : -1)
-#endif /* VMS */
-
 #ifndef LIBRARY_PATH_ENV
 #define LIBRARY_PATH_ENV "LIBRARY_PATH"
 #endif
@@ -66,8 +52,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    the utilities are not correct for a cross-compiler; we have to hope that
    cross-versions are in the proper directories.  */
 
-#ifdef CROSS_COMPILE
-#undef SUNOS4_SHARED_LIBRARIES
+#ifdef CROSS_DIRECTORY_STRUCTURE
 #undef OBJECT_FORMAT_COFF
 #undef MD_EXEC_PREFIX
 #undef REAL_LD_FILE_NAME
@@ -140,7 +125,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
   fprintf ((STREAM), "void _GLOBAL__DD() {\n\t%s();\n}\n", (FUNC))
 #endif
 
-#if defined (LDD_SUFFIX) || SUNOS4_SHARED_LIBRARIES
+#ifdef LDD_SUFFIX
 #define SCAN_LIBRARIES
 #endif
 
@@ -150,10 +135,6 @@ int do_collecting = 1;
 int do_collecting = 0;
 #endif
 
-#ifndef COLLECT_PARSE_FLAG
-#define COLLECT_PARSE_FLAG(FLAG)
-#endif
-
 /* Nonzero if we should suppress the automatic demangling of identifiers
    in linker error messages.  Set from COLLECT_NO_DEMANGLE.  */
 int no_demangle;
@@ -179,35 +160,38 @@ struct head
 enum pass {
   PASS_FIRST,                          /* without constructors */
   PASS_OBJ,                            /* individual objects */
-  PASS_LIB,                            /* looking for shared libraries */
+  PASS_LIB,                            /* looking for shared libraries */
   PASS_SECOND                          /* with constructors linked in */
 };
 
 int vflag;                             /* true if -v */
 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 */
 #endif
 
 int debug;                             /* true if -debug */
 
-static int shared_obj;                 /* true if -shared */
+static int shared_obj;                 /* true if -shared */
 
 static const char *c_file;             /* <xxx>.c for constructor/destructor list.  */
 static const char *o_file;             /* <xxx>.o for constructor/destructor list.  */
 #ifdef COLLECT_EXPORT_LIST
-static const char *export_file;                /* <xxx>.x for AIX export list.  */
+static const char *export_file;                /* <xxx>.x for AIX export list.  */
 #endif
-const char *ldout;                     /* File for ld errors.  */
+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
 static const char *ldd_file_name;      /* pathname of ldd (or equivalent) */
 #endif
 static const char *strip_file_name;            /* pathname of strip */
-const char *c_file_name;               /* pathname of gcc */
+const char *c_file_name;               /* pathname of gcc */
 static char *initname, *fininame;      /* names of init and fini funcs */
 
 static struct head constructors;       /* list of constructors found */
@@ -217,12 +201,12 @@ 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 */
+
 struct obstack temporary_obstack;
 char * temporary_firstobj;
 
-/* Holds the return value of pexecute and fork.  */
-int pid;
-
 /* Structure to hold all the directories in which to search for files to
    execute.  */
 
@@ -246,7 +230,6 @@ 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,
                                          &libpath_lib_dirs, NULL};
-static const char *const libexts[3] = {"a", "so", NULL};  /* possible library extensions */
 #endif
 
 static void handler (int);
@@ -255,7 +238,7 @@ 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 *);
+static void do_wait (const char *, struct pex_obj *);
 static void fork_execute (const char *, char **);
 static void maybe_unlink (const char *);
 static void add_to_list (struct head *, const char *);
@@ -290,26 +273,6 @@ static char *resolve_lib_name (const char *);
 #endif
 static char *extract_string (const char **);
 \f
-#ifndef HAVE_DUP2
-static int
-dup2 (int oldfd, int newfd)
-{
-  int fdtmp[256];
-  int fdx = 0;
-  int fd;
-
-  if (oldfd == newfd)
-    return oldfd;
-  close (newfd);
-  while ((fd = dup (oldfd)) != newfd && fd >= 0) /* good enough for low fd's */
-    fdtmp[fdx++] = fd;
-  while (fdx > 0)
-    close (fdtmp[--fdx]);
-
-  return fd;
-}
-#endif /* ! HAVE_DUP2 */
-\f
 /* Delete tempfiles and exit function.  */
 
 void
@@ -328,39 +291,48 @@ collect_exit (int status)
 
   if (ldout != 0 && ldout[0])
     {
-      dump_file (ldout);
+      dump_file (ldout, stdout);
       maybe_unlink (ldout);
     }
 
+  if (lderrout != 0 && lderrout[0])
+    {
+      dump_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);
 }
 
 \f
 /* Notify user of a non-error.  */
 void
-notice (const char *msgid, ...)
+notice (const char *cmsgid, ...)
 {
   va_list ap;
 
-  va_start (ap, msgid);
-  vfprintf (stderr, _(msgid), ap);
+  va_start (ap, cmsgid);
+  vfprintf (stderr, _(cmsgid), ap);
   va_end (ap);
 }
 
 /* Die when sys call fails.  */
 
 void
-fatal_perror (const char * msgid, ...)
+fatal_perror (const char * cmsgid, ...)
 {
   int e = errno;
   va_list ap;
 
-  va_start (ap, msgid);
+  va_start (ap, cmsgid);
   fprintf (stderr, "collect2: ");
-  vfprintf (stderr, _(msgid), ap);
+  vfprintf (stderr, _(cmsgid), ap);
   fprintf (stderr, ": %s\n", xstrerror (e));
   va_end (ap);
 
@@ -370,13 +342,13 @@ fatal_perror (const char * msgid, ...)
 /* Just die.  */
 
 void
-fatal (const char * msgid, ...)
+fatal (const char * cmsgid, ...)
 {
   va_list ap;
 
-  va_start (ap, msgid);
+  va_start (ap, cmsgid);
   fprintf (stderr, "collect2: ");
-  vfprintf (stderr, _(msgid), ap);
+  vfprintf (stderr, _(cmsgid), ap);
   fprintf (stderr, "\n");
   va_end (ap);
 
@@ -386,13 +358,13 @@ fatal (const char * msgid, ...)
 /* Write error message.  */
 
 void
-error (const char * msgid, ...)
+error (const char * gmsgid, ...)
 {
   va_list ap;
 
-  va_start (ap, msgid);
+  va_start (ap, gmsgid);
   fprintf (stderr, "collect2: ");
-  vfprintf (stderr, _(msgid), ap);
+  vfprintf (stderr, _(gmsgid), ap);
   fprintf (stderr, "\n");
   va_end(ap);
 }
@@ -401,9 +373,9 @@ error (const char * msgid, ...)
    provide a default entry.  */
 
 void
-fancy_abort (void)
+fancy_abort (const char *file, int line, const char *func)
 {
-  fatal ("internal error");
+  fatal ("internal gcc abort in %s, at %s:%d", func, file, line);
 }
 \f
 static void
@@ -418,13 +390,19 @@ handler (int signo)
   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 (response_file)
+    maybe_unlink (response_file);
+
   signal (signo, SIG_DFL);
-  kill (getpid (), signo);
+  raise (signo);
 }
 
 \f
@@ -463,11 +441,11 @@ extract_string (const char **pp)
 
   obstack_1grow (&temporary_obstack, '\0');
   *pp = p;
-  return obstack_finish (&temporary_obstack);
+  return XOBFINISH (&temporary_obstack, char *);
 }
 \f
 void
-dump_file (const char *name)
+dump_file (const char *name, FILE *to)
 {
   FILE *stream = fopen (name, "r");
 
@@ -484,41 +462,55 @@ dump_file (const char *name)
          const char *word, *p;
          char *result;
          obstack_1grow (&temporary_obstack, '\0');
-         word = obstack_finish (&temporary_obstack);
+         word = XOBFINISH (&temporary_obstack, const char *);
 
          if (*word == '.')
-           ++word, putc ('.', stderr);
+           ++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, stderr);
+             fputs (result, to);
 
              diff = strlen (word) - strlen (result);
              while (diff > 0 && c == ' ')
-               --diff, putc (' ', stderr);
-             while (diff < 0 && c == ' ')
-               ++diff, c = getc (stream);
+               --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, stderr);
+           fputs (word, to);
 
-         fflush (stderr);
+         fflush (to);
          obstack_free (&temporary_obstack, temporary_firstobj);
        }
       if (c == EOF)
        break;
-      putc (c, stderr);
+      putc (c, to);
     }
   fclose (stream);
 }
@@ -579,7 +571,7 @@ is_ctor_dtor (const char *s)
 
 static struct path_prefix cpath, path;
 
-#ifdef CROSS_COMPILE
+#ifdef CROSS_DIRECTORY_STRUCTURE
 /* This is the name of the target machine.  We use it to form the name
    of the files to execute.  */
 
@@ -605,7 +597,7 @@ find_a_file (struct path_prefix *pprefix, const char *name)
   len += strlen (HOST_EXECUTABLE_SUFFIX);
 #endif
 
-  temp = xmalloc (len);
+  temp = XNEWVEC (char, len);
 
   /* Determine the filename to execute (special case for absolute paths).  */
 
@@ -693,7 +685,7 @@ add_prefix (struct path_prefix *pprefix, const char *prefix)
   if (len > pprefix->max_len)
     pprefix->max_len = len;
 
-  pl = xmalloc (sizeof (struct prefix_list));
+  pl = XNEW (struct prefix_list);
   pl->prefix = xstrdup (prefix);
 
   if (*prev)
@@ -720,7 +712,7 @@ static void
 prefix_from_string (const char *p, struct path_prefix *pprefix)
 {
   const char *startp, *endp;
-  char *nstore = xmalloc (strlen (p) + 3);
+  char *nstore = XNEWVEC (char, strlen (p) + 3);
 
   if (debug)
     fprintf (stderr, "Convert string '%s' into prefixes, separator = '%c'\n", p, PATH_SEPARATOR);
@@ -754,6 +746,7 @@ prefix_from_string (const char *p, struct path_prefix *pprefix)
       else
        endp++;
     }
+  free (nstore);
 }
 \f
 /* Main program.  */
@@ -772,7 +765,7 @@ main (int argc, char **argv)
   static const char *const strip_suffix = "strip";
   static const char *const gstrip_suffix = "gstrip";
 
-#ifdef CROSS_COMPILE
+#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
@@ -801,7 +794,7 @@ main (int argc, char **argv)
 #endif
   const char *const full_strip_suffix  = strip_suffix;
   const char *const full_gstrip_suffix = gstrip_suffix;
-#endif /* CROSS_COMPILE */
+#endif /* CROSS_DIRECTORY_STRUCTURE */
 
   const char *arg;
   FILE *outf;
@@ -819,7 +812,15 @@ main (int argc, char **argv)
   char **object_lst;
   const char **object;
   int first_file;
-  int num_c_args       = argc+9;
+  int num_c_args;
+  char **old_argv;
+
+  old_argv = argv;
+  expandargv (&argc, &argv);
+  if (argv != old_argv)
+    at_file_supplied = 1;
+
+  num_c_args = argc + 9;
 
   no_demangle = !! getenv ("COLLECT_NO_DEMANGLE");
 
@@ -837,13 +838,16 @@ main (int argc, char **argv)
   signal (SIGCHLD, SIG_DFL);
 #endif
 
+  /* Unlock the stdio streams.  */
+  unlock_std_streams ();
+
   gcc_init_libintl ();
 
   /* Do not invoke xcalloc before this point, since locale needs to be
      set first, in case a diagnostic is issued.  */
 
-  ld1 = (const char **)(ld1_argv = xcalloc(sizeof (char *), argc+3));
-  ld2 = (const char **)(ld2_argv = xcalloc(sizeof (char *), argc+10));
+  ld1 = (const char **)(ld1_argv = xcalloc(sizeof (char *), argc+4));
+  ld2 = (const char **)(ld2_argv = xcalloc(sizeof (char *), argc+11));
   object = (const char **)(object_lst = xcalloc(sizeof (char *), argc));
 
 #ifdef DEBUG
@@ -860,7 +864,6 @@ main (int argc, char **argv)
       {
        if (! strcmp (argv[i], "-debug"))
          debug = 1;
-       COLLECT_PARSE_FLAG (argv[i]);
       }
     vflag = debug;
   }
@@ -874,7 +877,9 @@ main (int argc, char **argv)
   obstack_begin (&temporary_obstack, 0);
   temporary_firstobj = obstack_alloc (&temporary_obstack, 0);
 
+#ifndef HAVE_LD_DEMANGLE
   current_demangling_style = auto_demangling;
+#endif
   p = getenv ("COLLECT_GCC_OPTIONS");
   while (p && *p)
     {
@@ -884,8 +889,9 @@ main (int argc, char **argv)
     }
   obstack_free (&temporary_obstack, temporary_firstobj);
 
-  /* -fno-exceptions -w */
-  num_c_args += 2;
+  /* -fno-profile-arcs -fno-test-coverage -fno-branch-probabilities
+     -fno-exceptions -w */
+  num_c_args += 5;
 
   c_ptr = (const char **) (c_argv = xcalloc (sizeof (char *), num_c_args));
 
@@ -978,7 +984,7 @@ main (int argc, char **argv)
   c_file_name = getenv ("COLLECT_GCC");
   if (c_file_name == 0)
     {
-#ifdef CROSS_COMPILE
+#ifdef CROSS_DIRECTORY_STRUCTURE
       c_file_name = concat (target_machine, "-gcc", NULL);
 #else
       c_file_name = "gcc";
@@ -1004,6 +1010,7 @@ main (int argc, char **argv)
   export_file = make_temp_file (".x");
 #endif
   ldout = make_temp_file (".ld");
+  lderrout = make_temp_file (".le");
   *c_ptr++ = c_file_name;
   *c_ptr++ = "-x";
   *c_ptr++ = "c";
@@ -1046,6 +1053,9 @@ main (int argc, char **argv)
        }
     }
   obstack_free (&temporary_obstack, temporary_firstobj);
+  *c_ptr++ = "-fno-profile-arcs";
+  *c_ptr++ = "-fno-test-coverage";
+  *c_ptr++ = "-fno-branch-probabilities";
   *c_ptr++ = "-fno-exceptions";
   *c_ptr++ = "-w";
 
@@ -1060,6 +1070,12 @@ main (int argc, char **argv)
   /* 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;
@@ -1073,9 +1089,11 @@ main (int argc, char **argv)
               explicitly puts an export list in command line */
            case 'b':
              if (arg[2] == 'E' || strncmp (&arg[2], "export", 6) == 0)
-                export_flag = 1;
+               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;
              break;
 #endif
 
@@ -1086,6 +1104,11 @@ main (int argc, char **argv)
                  ld1--;
                  ld2--;
                }
+             if (!strcmp (arg, "-dynamic-linker") && argv[1])
+               {
+                 ++argv;
+                 *ld1++ = *ld2++ = *argv;
+               }
              break;
 
            case 'l':
@@ -1099,7 +1122,7 @@ main (int argc, char **argv)
                }
 #ifdef COLLECT_EXPORT_LIST
              {
-               /* Resolving full library name.  */
+               /* Resolving full library name.  */
                const char *s = resolve_lib_name (arg+2);
 
                /* Saving a full library name.  */
@@ -1154,6 +1177,34 @@ main (int argc, char **argv)
              if (arg[2] == '\0')
                vflag = 1;
              break;
+
+           case '-':
+             if (strcmp (arg, "--no-demangle") == 0)
+               {
+                 demangle_flag = arg;
+                 no_demangle = 1;
+                 ld1--;
+                 ld2--;
+               }
+             else if (strncmp (arg, "--demangle", 10) == 0)
+               {
+                 demangle_flag = arg;
+                 no_demangle = 0;
+#ifndef HAVE_LD_DEMANGLE
+                 if (arg[10] == '=')
+                   {
+                     enum demangling_styles style
+                       = cplus_demangle_name_to_style (arg+11);
+                     if (style == unknown_demangling)
+                       error ("unknown demangling style '%s'", arg+11);
+                     else
+                       current_demangling_style = style;
+                   }
+#endif
+                 ld1--;
+                 ld2--;
+               }
+             break;
            }
        }
       else if ((p = strrchr (arg, '.')) != (char *) 0
@@ -1181,8 +1232,8 @@ main (int argc, char **argv)
          else
            {
              /* Saving a full library name.  */
-              add_to_list (&libs, arg);
-            }
+             add_to_list (&libs, arg);
+           }
 #endif
        }
     }
@@ -1343,7 +1394,7 @@ main (int argc, char **argv)
       /* Strip now if it was requested on the command line.  */
       if (strip_flag)
        {
-         char **real_strip_argv = xcalloc (sizeof (char *), 3);
+         char **real_strip_argv = XCNEWVEC (char *, 3);
          const char ** strip_argv = (const char **) real_strip_argv;
 
          strip_argv[0] = strip_file_name;
@@ -1394,10 +1445,12 @@ main (int argc, char **argv)
       if (! exports.first)
        *ld2++ = concat ("-bE:", export_file, NULL);
 
+#ifndef LD_INIT_SWITCH
       add_to_list (&exports, initname);
       add_to_list (&exports, fininame);
       add_to_list (&exports, "_GLOBAL__DI");
       add_to_list (&exports, "_GLOBAL__DD");
+#endif
       exportf = fopen (export_file, "w");
       if (exportf == (FILE *) 0)
        fatal_perror ("fopen %s", export_file);
@@ -1428,10 +1481,10 @@ main (int argc, char **argv)
 
   fork_execute ("gcc",  c_argv);
 #ifdef COLLECT_EXPORT_LIST
-  /* On AIX we must call tlink because of possible templates resolution */
+  /* On AIX we must call tlink because of possible templates resolution */
   do_tlink (ld2_argv, object_lst);
 #else
-  /* Otherwise, simply call ld because tlink is already done */
+  /* Otherwise, simply call ld because tlink is already done */
   fork_execute ("ld", ld2_argv);
 
   /* Let scan_prog_file do any final mods (OSF/rose needs this for
@@ -1453,11 +1506,14 @@ main (int argc, char **argv)
 /* Wait for a process to finish, and exit if a nonzero status is found.  */
 
 int
-collect_wait (const char *prog)
+collect_wait (const char *prog, struct pex_obj *pex)
 {
   int status;
 
-  pwait (pid, &status, 0);
+  if (!pex_get_status (pex, 1, &status))
+    fatal_perror ("can't get program status");
+  pex_free (pex);
+
   if (status)
     {
       if (WIFSIGNALED (status))
@@ -1476,27 +1532,73 @@ collect_wait (const char *prog)
 }
 
 static void
-do_wait (const char *prog)
+do_wait (const char *prog, struct pex_obj *pex)
 {
-  int ret = collect_wait (prog);
+  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;
+    }
 }
 
 \f
 /* Execute a program, and wait for the reply.  */
 
-void
-collect_execute (const char *prog, char **argv, const char *redir)
+struct pex_obj *
+collect_execute (const char *prog, char **argv, const char *outname,
+                const char *errname)
 {
-  char *errmsg_fmt;
-  char *errmsg_arg;
-  int redir_handle = -1;
-  int stdout_save = -1;
-  int stderr_save = -1;
+  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)
     {
@@ -1521,49 +1623,38 @@ collect_execute (const char *prog, char **argv, const char *redir)
      since we might not end up needing something that we could not find.  */
 
   if (argv[0] == 0)
-    fatal ("cannot find `%s'", prog);
-
-  if (redir)
-    {
-      /* Open response file.  */
-      redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT);
-
-      /* Duplicate the stdout and stderr file handles
-        so they can be restored later.  */
-      stdout_save = dup (STDOUT_FILENO);
-      if (stdout_save == -1)
-       fatal_perror ("redirecting stdout: %s", redir);
-      stderr_save = dup (STDERR_FILENO);
-      if (stderr_save == -1)
-       fatal_perror ("redirecting stdout: %s", redir);
-
-      /* Redirect stdout & stderr to our response file.  */
-      dup2 (redir_handle, STDOUT_FILENO);
-      dup2 (redir_handle, STDERR_FILENO);
-    }
+    fatal ("cannot find '%s'", prog);
 
-  pid = pexecute (argv[0], argv, argv[0], NULL, &errmsg_fmt, &errmsg_arg,
-                 (PEXECUTE_FIRST | PEXECUTE_LAST | PEXECUTE_SEARCH));
+  pex = pex_init (0, "collect2", NULL);
+  if (pex == NULL)
+    fatal_perror ("pex_init failed");
 
-  if (redir)
+  errmsg = pex_run (pex, PEX_LAST | PEX_SEARCH, argv[0], argv, outname,
+                   errname, &err);
+  if (errmsg != NULL)
     {
-      /* Restore stdout and stderr to their previous settings.  */
-      dup2 (stdout_save, STDOUT_FILENO);
-      dup2 (stderr_save, STDERR_FILENO);
-
-      /* Close response file.  */
-      close (redir_handle);
+      if (err != 0)
+       {
+         errno = err;
+         fatal_perror (errmsg);
+       }
+      else
+       fatal (errmsg);
     }
 
- if (pid == -1)
-   fatal_perror (errmsg_fmt, errmsg_arg);
+  if (response_arg)
+    free (response_arg);
+
+  return pex;
 }
 
 static void
 fork_execute (const char *prog, char **argv)
 {
-  collect_execute (prog, argv, NULL);
-  do_wait (prog);
+  struct pex_obj *pex;
+
+  pex = collect_execute (prog, argv, NULL, NULL);
+  do_wait (prog, pex);
 }
 \f
 /* Unlink a file unless we are debugging.  */
@@ -1572,7 +1663,7 @@ static void
 maybe_unlink (const char *file)
 {
   if (!debug)
-    unlink (file);
+    unlink_if_ordinary (file);
   else
     notice ("[Leaving %s]\n", file);
 }
@@ -1656,7 +1747,7 @@ sort_ids (struct head *head_ptr)
            || id->sequence > (*id_ptr)->sequence
            /* Hack: do lexical compare, too.
            || (id->sequence == (*id_ptr)->sequence
-               && strcmp (id->name, (*id_ptr)->name) > 0) */
+               && strcmp (id->name, (*id_ptr)->name) > 0) */
            )
          {
            id->next = *id_ptr;
@@ -1787,7 +1878,7 @@ write_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED)
        }
     }
   /* q points to null at end of the string (or . of the .so version) */
-  prefix = xmalloc (q - p + 1);
+  prefix = XNEWVEC (char, q - p + 1);
   strncpy (prefix, p, q - p);
   prefix[q - p] = 0;
   for (r = prefix; *r; r++)
@@ -1985,11 +2076,15 @@ static void
 scan_prog_file (const char *prog_name, enum pass which_pass)
 {
   void (*int_handler) (int);
+#ifdef SIGQUIT
   void (*quit_handler) (int);
+#endif
   char *real_nm_argv[4];
   const char **nm_argv = (const char **) real_nm_argv;
   int argc = 0;
-  int pipe_fd[2];
+  struct pex_obj *pex;
+  const char *errmsg;
+  int err;
   char *p, buf[1024];
   FILE *inf;
 
@@ -1998,7 +2093,7 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
 
   /* If we do not have an `nm', complain.  */
   if (nm_file_name == 0)
-    fatal ("cannot find `nm'");
+    fatal ("cannot find 'nm'");
 
   nm_argv[argc++] = nm_file_name;
   if (NM_FLAGS[0] != '\0')
@@ -2007,13 +2102,6 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
   nm_argv[argc++] = prog_name;
   nm_argv[argc++] = (char *) 0;
 
-  if (pipe (pipe_fd) < 0)
-    fatal_perror ("pipe");
-
-  inf = fdopen (pipe_fd[0], "r");
-  if (inf == (FILE *) 0)
-    fatal_perror ("fdopen");
-
   /* Trace if needed.  */
   if (vflag)
     {
@@ -2029,35 +2117,30 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
   fflush (stdout);
   fflush (stderr);
 
-  /* Spawn child nm on pipe.  */
-  pid = vfork ();
-  if (pid == -1)
-    fatal_perror (VFORK_STRING);
+  pex = pex_init (PEX_USE_PIPES, "collect2", NULL);
+  if (pex == NULL)
+    fatal_perror ("pex_init failed");
 
-  if (pid == 0)                        /* child context */
+  errmsg = pex_run (pex, 0, nm_file_name, real_nm_argv, NULL, NULL, &err);
+  if (errmsg != NULL)
     {
-      /* setup stdout */
-      if (dup2 (pipe_fd[1], 1) < 0)
-       fatal_perror ("dup2 %d 1", pipe_fd[1]);
-
-      if (close (pipe_fd[0]) < 0)
-       fatal_perror ("close %d", pipe_fd[0]);
-
-      if (close (pipe_fd[1]) < 0)
-       fatal_perror ("close %d", pipe_fd[1]);
-
-      execv (nm_file_name, real_nm_argv);
-      fatal_perror ("execv %s", nm_file_name);
+      if (err != 0)
+       {
+         errno = err;
+         fatal_perror (errmsg);
+       }
+      else
+       fatal (errmsg);
     }
 
-  /* Parent context from here on.  */
   int_handler  = (void (*) (int)) signal (SIGINT,  SIG_IGN);
 #ifdef SIGQUIT
   quit_handler = (void (*) (int)) signal (SIGQUIT, SIG_IGN);
 #endif
 
-  if (close (pipe_fd[1]) < 0)
-    fatal_perror ("close %d", pipe_fd[1]);
+  inf = pex_read_output (pex, 0);
+  if (inf == NULL)
+    fatal_perror ("can't open nm output");
 
   if (debug)
     fprintf (stderr, "\nnm output with constructors/destructors.\n");
@@ -2131,10 +2214,7 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
   if (debug)
     fprintf (stderr, "\n");
 
-  if (fclose (inf) != 0)
-    fatal_perror ("fclose");
-
-  do_wait (nm_file_name);
+  do_wait (nm_file_name, pex);
 
   signal (SIGINT,  int_handler);
 #ifdef SIGQUIT
@@ -2142,269 +2222,6 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
 #endif
 }
 
-#if SUNOS4_SHARED_LIBRARIES
-
-/* Routines to scan the SunOS 4 _DYNAMIC structure to find shared libraries
-   that the output file depends upon and their initialization/finalization
-   routines, if any.  */
-
-#include <a.out.h>
-#include <fcntl.h>
-#include <link.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-#include <unistd.h>
-#include <sys/dir.h>
-
-/* pointers to the object file */
-unsigned object;       /* address of memory mapped file */
-unsigned objsize;      /* size of memory mapped to file */
-char * code;           /* pointer to code segment */
-char * data;           /* pointer to data segment */
-struct nlist *symtab;  /* pointer to symbol table */
-struct link_dynamic *ld;
-struct link_dynamic_2 *ld_2;
-struct head libraries;
-
-/* Map the file indicated by NAME into memory and store its address.  */
-
-static void
-mapfile (const char *name)
-{
-  int fp;
-  struct stat s;
-  if ((fp = open (name, O_RDONLY)) == -1)
-    fatal ("unable to open file '%s'", name);
-  if (fstat (fp, &s) == -1)
-    fatal ("unable to stat file '%s'", name);
-
-  objsize = s.st_size;
-  object = (unsigned) mmap (0, objsize, PROT_READ|PROT_WRITE, MAP_PRIVATE,
-                           fp, 0);
-  if (object == (unsigned)-1)
-    fatal ("unable to mmap file '%s'", name);
-
-  close (fp);
-}
-
-/* Helpers for locatelib.  */
-
-static const char *libname;
-
-static int
-libselect (struct direct *d)
-{
-  return (strncmp (libname, d->d_name, strlen (libname)) == 0);
-}
-
-/* If one file has an additional numeric extension past LIBNAME, then put
-   that one first in the sort.  If both files have additional numeric
-   extensions, then put the one with the higher number first in the sort.
-
-   We must verify that the extension is numeric, because Sun saves the
-   original versions of patched libraries with a .FCS extension.  Files with
-   invalid extensions must go last in the sort, so that they will not be used.  */
-
-static int
-libcompare (struct direct **d1, struct direct **d2)
-{
-  int i1, i2 = strlen (libname);
-  char *e1 = (*d1)->d_name + i2;
-  char *e2 = (*d2)->d_name + i2;
-
-  while (*e1 && *e2 && *e1 == '.' && *e2 == '.'
-        && e1[1] && ISDIGIT (e1[1]) && e2[1] && ISDIGIT (e2[1]))
-    {
-      ++e1;
-      ++e2;
-      i1 = strtol (e1, &e1, 10);
-      i2 = strtol (e2, &e2, 10);
-      if (i1 != i2)
-       return i1 - i2;
-    }
-
-  if (*e1)
-    {
-      /* It has a valid numeric extension, prefer this one.  */
-      if (*e1 == '.' && e1[1] && ISDIGIT (e1[1]))
-       return 1;
-      /* It has an invalid numeric extension, must prefer the other one.  */
-      else
-       return -1;
-    }
-  else if (*e2)
-    {
-      /* It has a valid numeric extension, prefer this one.  */
-      if (*e2 == '.' && e2[1] && ISDIGIT (e2[1]))
-       return -1;
-      /* It has an invalid numeric extension, must prefer the other one.  */
-      else
-       return 1;
-    }
-  else
-    return 0;
-}
-
-/* Given the name NAME of a dynamic dependency, find its pathname and add
-   it to the list of libraries.  */
-
-static void
-locatelib (const char *name)
-{
-  static const char **l;
-  static int cnt;
-  char buf[MAXPATHLEN];
-  char *p, *q;
-  const char **pp;
-
-  if (l == 0)
-    {
-      char *ld_rules;
-      char *ldr = 0;
-      /* counting elements in array, need 1 extra for null */
-      cnt = 1;
-      ld_rules = (char *) (ld_2->ld_rules + code);
-      if (ld_rules)
-       {
-         cnt++;
-         for (; *ld_rules != 0; ld_rules++)
-           if (*ld_rules == ':')
-             cnt++;
-         ld_rules = (char *) (ld_2->ld_rules + code);
-         ldr = xstrdup (ld_rules);
-       }
-      p = getenv ("LD_LIBRARY_PATH");
-      q = 0;
-      if (p)
-       {
-         cnt++;
-         for (q = p ; *q != 0; q++)
-           if (*q == ':')
-             cnt++;
-         q = xstrdup (p);
-       }
-      l = xmalloc ((cnt + 3) * sizeof (char *));
-      pp = l;
-      if (ldr)
-       {
-         *pp++ = ldr;
-         for (; *ldr != 0; ldr++)
-           if (*ldr == ':')
-             {
-               *ldr++ = 0;
-               *pp++ = ldr;
-             }
-       }
-      if (q)
-       {
-         *pp++ = q;
-         for (; *q != 0; q++)
-           if (*q == ':')
-             {
-               *q++ = 0;
-               *pp++ = q;
-             }
-       }
-      /* built in directories are /lib, /usr/lib, and /usr/local/lib */
-      *pp++ = "/lib";
-      *pp++ = "/usr/lib";
-      *pp++ = "/usr/local/lib";
-      *pp = 0;
-    }
-  libname = name;
-  for (pp = l; *pp != 0 ; pp++)
-    {
-      struct direct **namelist;
-      int entries;
-      if ((entries = scandir (*pp, &namelist, libselect, libcompare)) > 0)
-       {
-         sprintf (buf, "%s/%s", *pp, namelist[entries - 1]->d_name);
-         add_to_list (&libraries, buf);
-         if (debug)
-           fprintf (stderr, "%s\n", buf);
-         break;
-       }
-    }
-  if (*pp == 0)
-    {
-      if (debug)
-       notice ("not found\n");
-      else
-       fatal ("dynamic dependency %s not found", name);
-    }
-}
-
-/* Scan the _DYNAMIC structure of the output file to find shared libraries
-   that it depends upon and any constructors or destructors they contain.  */
-
-static void
-scan_libraries (const char *prog_name)
-{
-  struct exec *header;
-  char *base;
-  struct link_object *lo;
-  char buff[MAXPATHLEN];
-  struct id *list;
-
-  mapfile (prog_name);
-  header = (struct exec *)object;
-  if (N_BADMAG (*header))
-    fatal ("bad magic number in file '%s'", prog_name);
-  if (header->a_dynamic == 0)
-    return;
-
-  code = (char *) (N_TXTOFF (*header) + (long) header);
-  data = (char *) (N_DATOFF (*header) + (long) header);
-  symtab = (struct nlist *) (N_SYMOFF (*header) + (long) header);
-
-  if (header->a_magic == ZMAGIC && header->a_entry == 0x20)
-    {
-      /* shared object */
-      ld = (struct link_dynamic *) (symtab->n_value + code);
-      base = code;
-    }
-  else
-    {
-      /* executable */
-      ld = (struct link_dynamic *) data;
-      base = code-PAGSIZ;
-    }
-
-  if (debug)
-    notice ("dynamic dependencies.\n");
-
-  ld_2 = (struct link_dynamic_2 *) ((long) ld->ld_un.ld_2 + (long)base);
-  for (lo = (struct link_object *) ld_2->ld_need; lo;
-       lo = (struct link_object *) lo->lo_next)
-    {
-      char *name;
-      lo = (struct link_object *) ((long) lo + code);
-      name = (char *) (code + lo->lo_name);
-      if (lo->lo_library)
-       {
-         if (debug)
-           fprintf (stderr, "\t-l%s.%d => ", name, lo->lo_major);
-         sprintf (buff, "lib%s.so.%d.%d", name, lo->lo_major, lo->lo_minor);
-         locatelib (buff);
-       }
-      else
-       {
-         if (debug)
-           fprintf (stderr, "\t%s\n", name);
-         add_to_list (&libraries, name);
-       }
-    }
-
-  if (debug)
-    fprintf (stderr, "\n");
-
-  /* now iterate through the library list adding their symbols to
-     the list.  */
-  for (list = libraries.first; list; list = list->next)
-    scan_prog_file (list->name, PASS_LIB);
-}
-
-#else  /* SUNOS4_SHARED_LIBRARIES */
 #ifdef LDD_SUFFIX
 
 /* Use the List Dynamic Dependencies program to find shared libraries that
@@ -2417,18 +2234,22 @@ scan_libraries (const char *prog_name)
   static struct head libraries;                /* list of shared libraries found */
   struct id *list;
   void (*int_handler) (int);
+#ifdef SIGQUIT
   void (*quit_handler) (int);
+#endif
   char *real_ldd_argv[4];
   const char **ldd_argv = (const char **) real_ldd_argv;
   int argc = 0;
-  int pipe_fd[2];
+  struct pex_obj *pex;
+  const char *errmsg;
+  int err;
   char buf[1024];
   FILE *inf;
 
   /* If we do not have an `ldd', complain.  */
   if (ldd_file_name == 0)
     {
-      error ("cannot find `ldd'");
+      error ("cannot find 'ldd'");
       return;
     }
 
@@ -2436,13 +2257,6 @@ scan_libraries (const char *prog_name)
   ldd_argv[argc++] = prog_name;
   ldd_argv[argc++] = (char *) 0;
 
-  if (pipe (pipe_fd) < 0)
-    fatal_perror ("pipe");
-
-  inf = fdopen (pipe_fd[0], "r");
-  if (inf == (FILE *) 0)
-    fatal_perror ("fdopen");
-
   /* Trace if needed.  */
   if (vflag)
     {
@@ -2458,35 +2272,30 @@ scan_libraries (const char *prog_name)
   fflush (stdout);
   fflush (stderr);
 
-  /* Spawn child ldd on pipe.  */
-  pid = vfork ();
-  if (pid == -1)
-    fatal_perror (VFORK_STRING);
+  pex = pex_init (PEX_USE_PIPES, "collect2", NULL);
+  if (pex == NULL)
+    fatal_perror ("pex_init failed");
 
-  if (pid == 0)                        /* child context */
+  errmsg = pex_run (pex, 0, ldd_file_name, real_ldd_argv, NULL, NULL, &err);
+  if (errmsg != NULL)
     {
-      /* setup stdout */
-      if (dup2 (pipe_fd[1], 1) < 0)
-       fatal_perror ("dup2 %d 1", pipe_fd[1]);
-
-      if (close (pipe_fd[0]) < 0)
-       fatal_perror ("close %d", pipe_fd[0]);
-
-      if (close (pipe_fd[1]) < 0)
-       fatal_perror ("close %d", pipe_fd[1]);
-
-      execv (ldd_file_name, real_ldd_argv);
-      fatal_perror ("execv %s", ldd_file_name);
+      if (err != 0)
+       {
+         errno = err;
+         fatal_perror (errmsg);
+       }
+      else
+       fatal (errmsg);
     }
 
-  /* Parent context from here on.  */
-  int_handler  = (void (*) (int))) signal (SIGINT,  SIG_IGN;
+  int_handler  = (void (*) (int)) signal (SIGINT,  SIG_IGN);
 #ifdef SIGQUIT
-  quit_handler = (void (*) (int))) signal (SIGQUIT, SIG_IGN;
+  quit_handler = (void (*) (int)) signal (SIGQUIT, SIG_IGN);
 #endif
 
-  if (close (pipe_fd[1]) < 0)
-    fatal_perror ("close %d", pipe_fd[1]);
+  inf = pex_read_output (pex, 0);
+  if (inf == NULL)
+    fatal_perror ("can't open ldd output");
 
   if (debug)
     notice ("\nldd output with constructors/destructors.\n");
@@ -2514,7 +2323,7 @@ scan_libraries (const char *prog_name)
       *end = '\0';
 
       if (access (name, R_OK) == 0)
-        add_to_list (&libraries, name);
+       add_to_list (&libraries, name);
       else
        fatal ("unable to open dynamic dependency '%s'", buf);
 
@@ -2524,24 +2333,20 @@ scan_libraries (const char *prog_name)
   if (debug)
     fprintf (stderr, "\n");
 
-  if (fclose (inf) != 0)
-    fatal_perror ("fclose");
-
-  do_wait (ldd_file_name);
+  do_wait (ldd_file_name, pex);
 
   signal (SIGINT,  int_handler);
 #ifdef SIGQUIT
   signal (SIGQUIT, quit_handler);
 #endif
 
-  /* now iterate through the library list adding their symbols to
+  /* Now iterate through the library list adding their symbols to
      the list.  */
   for (list = libraries.first; list; list = list->next)
     scan_prog_file (list->name, PASS_LIB);
 }
 
 #endif /* LDD_SUFFIX */
-#endif /* SUNOS4_SHARED_LIBRARIES */
 
 #endif /* OBJECT_FORMAT_NONE */
 
@@ -2552,7 +2357,7 @@ scan_libraries (const char *prog_name)
 
 #ifdef OBJECT_FORMAT_COFF
 
-#if defined(EXTENDED_COFF)
+#if defined (EXTENDED_COFF)
 
 #   define GCC_SYMBOLS(X)      (SYMHEADER(X).isymMax + SYMHEADER(X).iextMax)
 #   define GCC_SYMENT          SYMR
@@ -2565,14 +2370,26 @@ scan_libraries (const char *prog_name)
 
 #   define GCC_SYMBOLS(X)      (HEADER(ldptr).f_nsyms)
 #   define GCC_SYMENT          SYMENT
-#   define GCC_OK_SYMBOL(X) \
-     (((X).n_sclass == C_EXT) && \
-      ((X).n_scnum > N_UNDEF) && \
-      (aix64_flag \
-       || (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) \
-           || ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT))))
-#   define GCC_UNDEF_SYMBOL(X) \
-     (((X).n_sclass == C_EXT) && ((X).n_scnum == N_UNDEF))
+#   if defined (C_WEAKEXT)
+#     define GCC_OK_SYMBOL(X) \
+       (((X).n_sclass == C_EXT || (X).n_sclass == C_WEAKEXT) && \
+       ((X).n_scnum > N_UNDEF) && \
+       (aix64_flag \
+        || (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) \
+            || ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT))))
+#     define GCC_UNDEF_SYMBOL(X) \
+       (((X).n_sclass == C_EXT || (X).n_sclass == C_WEAKEXT) && \
+       ((X).n_scnum == N_UNDEF))
+#   else
+#     define GCC_OK_SYMBOL(X) \
+       (((X).n_sclass == C_EXT) && \
+       ((X).n_scnum > N_UNDEF) && \
+       (aix64_flag \
+        || (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) \
+            || ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT))))
+#     define GCC_UNDEF_SYMBOL(X) \
+       (((X).n_sclass == C_EXT) && ((X).n_scnum == N_UNDEF))
+#   endif
 #   define GCC_SYMINC(X)       ((X).n_numaux+1)
 #   define GCC_SYMZERO(X)      0
 
@@ -2658,9 +2475,9 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
     {
 #endif
       /* Some platforms (e.g. OSF4) declare ldopen as taking a
-         non-const char * filename parameter, even though it will not
-         modify that string.  So we must cast away const-ness here,
-         which will cause -Wcast-qual to burp.  */
+        non-const char * filename parameter, even though it will not
+        modify that string.  So we must cast away const-ness here,
+        which will cause -Wcast-qual to burp.  */
       if ((ldptr = ldopen ((char *)prog_name, ldptr)) != NULL)
        {
          if (! MY_ISCOFF (HEADER (ldptr).f_magic))
@@ -2689,7 +2506,7 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
                      char *name;
 
                      if ((name = ldgetname (ldptr, &symbol)) == NULL)
-                       continue;               /* should never happen */
+                       continue;               /* Should never happen.  */
 
 #ifdef XCOFF_DEBUGGING_INFO
                      /* All AIX function names have a duplicate entry
@@ -2703,7 +2520,7 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
                        case 1:
                          if (! is_shared)
                            add_to_list (&constructors, name);
-#ifdef COLLECT_EXPORT_LIST
+#if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
                          if (which_pass == PASS_OBJ)
                            add_to_list (&exports, name);
 #endif
@@ -2712,7 +2529,7 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
                        case 2:
                          if (! is_shared)
                            add_to_list (&destructors, name);
-#ifdef COLLECT_EXPORT_LIST
+#if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
                          if (which_pass == PASS_OBJ)
                            add_to_list (&exports, name);
 #endif
@@ -2737,7 +2554,7 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
                        case 5:
                          if (! is_shared)
                            add_to_list (&frame_tables, name);
-#ifdef COLLECT_EXPORT_LIST
+#if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
                          if (which_pass == PASS_OBJ)
                            add_to_list (&exports, name);
 #endif
@@ -2745,13 +2562,14 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
 
                        default:        /* not a constructor or destructor */
 #ifdef COLLECT_EXPORT_LIST
-                         /* If we are building a shared object on AIX we need
-                            to explicitly export all global symbols.  */
-                         if (shared_obj)
-                           {
-                             if (which_pass == PASS_OBJ && (! export_flag))
-                               add_to_list (&exports, name);
-                           }
+                         /* Explicitly export all global symbols when
+                            building a shared object on AIX, but do not
+                            re-export symbols from another shared object
+                            and do not export symbols if the user
+                            provides an explicit export list.  */
+                         if (shared_obj && !is_shared
+                             && which_pass == PASS_OBJ && !export_flag)
+                           add_to_list (&exports, name);
 #endif
                          continue;
                        }
@@ -2804,6 +2622,8 @@ resolve_lib_name (const char *name)
 {
   char *lib_buf;
   int i, j, l = 0;
+  /* Library extensions for AIX dynamic linking.  */
+  const char * const libexts[2] = {"a", "so"};
 
   for (i = 0; libpaths[i]; i++)
     if (libpaths[i]->max_len > l)
@@ -2822,14 +2642,15 @@ resolve_lib_name (const char *name)
          const char *p = "";
          if (list->prefix[strlen(list->prefix)-1] != '/')
            p = "/";
-         for (j = 0; libexts[j]; j++)
+         for (j = 0; j < 2; j++)
            {
              sprintf (lib_buf, "%s%slib%s.%s",
-                      list->prefix, p, name, libexts[j]);
-if (debug) fprintf (stderr, "searching for: %s\n", lib_buf);
+                      list->prefix, p, name,
+                      libexts[(j + aixrtl_flag) % 2]);
+             if (debug) fprintf (stderr, "searching for: %s\n", lib_buf);
              if (file_exists (lib_buf))
                {
-if (debug) fprintf (stderr, "found: %s\n", lib_buf);
+                 if (debug) fprintf (stderr, "found: %s\n", lib_buf);
                  return (lib_buf);
                }
            }