OSDN Git Service

v3: fix config.status instantiation of subdir makefiles.
[pf3gnuchains/gcc-fork.git] / gcc / collect2.c
index c6c1f3f..b235f2b 100644 (file)
@@ -1,7 +1,8 @@
 /* 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 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
+   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 +11,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 +20,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, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, 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.  */
@@ -42,6 +42,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #define COLLECT
 
 #include "collect2.h"
+#include "collect2-aix.h"
 #include "demangle.h"
 #include "obstack.h"
 #include "intl.h"
@@ -54,7 +55,9 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
    cross-versions are in the proper directories.  */
 
 #ifdef CROSS_DIRECTORY_STRUCTURE
+#ifndef CROSS_AIX_SUPPORT
 #undef OBJECT_FORMAT_COFF
+#endif
 #undef MD_EXEC_PREFIX
 #undef REAL_LD_FILE_NAME
 #undef REAL_NM_FILE_NAME
@@ -72,6 +75,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 
 #ifdef OBJECT_FORMAT_COFF
 
+#ifndef CROSS_DIRECTORY_STRUCTURE
 #include <a.out.h>
 #include <ar.h>
 
@@ -86,6 +90,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #endif
 
 #include <ldfcn.h>
+#endif
 
 /* Some systems have an ISCOFF macro, but others do not.  In some cases
    the macro may be wrong.  MY_ISCOFF is defined in tm.h files for machines
@@ -130,12 +135,25 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #define SCAN_LIBRARIES
 #endif
 
+#ifndef SHLIB_SUFFIX
+#define SHLIB_SUFFIX ".so"
+#endif
+
 #ifdef USE_COLLECT2
 int do_collecting = 1;
 #else
 int do_collecting = 0;
 #endif
 
+/* Cook up an always defined indication of whether we proceed the
+   "EXPORT_LIST" way.  */
+
+#ifdef COLLECT_EXPORT_LIST
+#define DO_COLLECT_EXPORT_LIST 1
+#else
+#define DO_COLLECT_EXPORT_LIST 0
+#endif
+
 /* Nonzero if we should suppress the automatic demangling of identifiers
    in linker error messages.  Set from COLLECT_NO_DEMANGLE.  */
 int no_demangle;
@@ -156,15 +174,6 @@ struct head
   int number;
 };
 
-/* Enumeration giving which pass this is for scanning the program file.  */
-
-enum pass {
-  PASS_FIRST,                          /* without constructors */
-  PASS_OBJ,                            /* individual objects */
-  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 */
@@ -202,9 +211,20 @@ 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;
 
+/* A string that must be prepended to a target OS path in order to find
+   it on the host system.  */
+#ifdef TARGET_SYSTEM_ROOT
+static const char *target_system_root = TARGET_SYSTEM_ROOT;
+#else
+static const char *target_system_root = "";
+#endif
+
 /* Structure to hold all the directories in which to search for files to
    execute.  */
 
@@ -230,8 +250,21 @@ static struct path_prefix *libpaths[3] = {&cmdline_lib_dirs,
                                          &libpath_lib_dirs, NULL};
 #endif
 
+/* Special kinds of symbols that a name may denote.  */
+
+typedef enum {
+  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;
+
+static symkind is_ctor_dtor (const char *);
+
 static void handler (int);
-static int is_ctor_dtor (const char *);
 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 *);
@@ -255,7 +288,6 @@ static void write_c_file_stat (FILE *, const char *);
 #ifndef LD_INIT_SWITCH
 static void write_c_file_glob (FILE *, const char *);
 #endif
-static void scan_prog_file (const char *, enum pass);
 #ifdef SCAN_LIBRARIES
 static void scan_libraries (const char *);
 #endif
@@ -270,6 +302,50 @@ static void write_aix_file (FILE *, struct id *);
 static char *resolve_lib_name (const char *);
 #endif
 static char *extract_string (const char **);
+
+/* Enumerations describing which pass this is for scanning the
+   program file ...  */
+
+typedef enum {
+  PASS_FIRST,                          /* without constructors */
+  PASS_OBJ,                            /* individual objects */
+  PASS_LIB,                            /* looking for shared libraries */
+  PASS_SECOND                          /* with constructors linked in */
+} scanpass;
+
+/* ... and which kinds of symbols are to be considered.  */
+
+enum scanfilter_masks {
+  SCAN_NOTHING = 0,
+
+  SCAN_CTOR = 1 << SYM_CTOR, 
+  SCAN_DTOR = 1 << SYM_DTOR,
+  SCAN_INIT = 1 << SYM_INIT,
+  SCAN_FINI = 1 << SYM_FINI,
+  SCAN_DWEH = 1 << SYM_DWEH,
+  SCAN_ALL  = ~0
+};
+
+/* This type is used for parameters and variables which hold
+   combinations of the flags in enum scanfilter_masks.  */
+typedef int scanfilter;
+
+/* Scan the name list of the loaded program for the symbols g++ uses for
+   static constructors and destructors.
+
+   The SCANPASS argument tells which collect processing pass this is for and
+   the SCANFILTER argument tells which kinds of symbols to consider in this
+   pass.  Symbols of a special kind not in the filter mask are considered as
+   regular ones.
+
+   The constructor table begins at __CTOR_LIST__ and contains a count of the
+   number of pointers (or -1 if the constructors are built in a separate
+   section by the linker), followed by the pointers to the constructor
+   functions, terminated with a null pointer.  The destructor table has the
+   same format, and begins at __DTOR_LIST__.  */
+
+static void scan_prog_file (const char *, scanpass, scanfilter);
+
 \f
 /* Delete tempfiles and exit function.  */
 
@@ -302,6 +378,9 @@ collect_exit (int status)
   if (status != 0 && output_file != 0 && output_file[0])
     maybe_unlink (output_file);
 
+  if (response_file)
+    maybe_unlink (response_file);
+
   exit (status);
 }
 
@@ -393,6 +472,9 @@ handler (int signo)
     maybe_unlink (export_file);
 #endif
 
+  if (response_file)
+    maybe_unlink (response_file);
+
   signal (signo, SIG_DFL);
   raise (signo);
 }
@@ -479,8 +561,18 @@ dump_file (const char *name, FILE *to)
              diff = strlen (word) - strlen (result);
              while (diff > 0 && c == ' ')
                --diff, putc (' ', to);
-             while (diff < 0 && c == ' ')
-               ++diff, c = getc (stream);
+             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);
            }
@@ -497,15 +589,12 @@ dump_file (const char *name, FILE *to)
   fclose (stream);
 }
 \f
-/* Decide whether the given symbol is: a constructor (1), a destructor
-   (2), a routine in a shared object that calls all the constructors
-   (3) or destructors (4), a DWARF exception-handling table (5), or
-   nothing special (0).  */
+/* Return the kind of symbol denoted by name S.  */
 
-static int
+static symkind
 is_ctor_dtor (const char *s)
 {
-  struct names { const char *const name; const int len; const int ret;
+  struct names { const char *const name; const int len; symkind ret;
     const int two_underscores; };
 
   const struct names *p;
@@ -514,27 +603,27 @@ is_ctor_dtor (const char *s)
 
   static const struct names special[] = {
 #ifndef NO_DOLLAR_IN_LABEL
-    { "GLOBAL__I$", sizeof ("GLOBAL__I$")-1, 1, 0 },
-    { "GLOBAL__D$", sizeof ("GLOBAL__D$")-1, 2, 0 },
+    { "GLOBAL__I$", sizeof ("GLOBAL__I$")-1, SYM_CTOR, 0 },
+    { "GLOBAL__D$", sizeof ("GLOBAL__D$")-1, SYM_DTOR, 0 },
 #else
 #ifndef NO_DOT_IN_LABEL
-    { "GLOBAL__I.", sizeof ("GLOBAL__I.")-1, 1, 0 },
-    { "GLOBAL__D.", sizeof ("GLOBAL__D.")-1, 2, 0 },
+    { "GLOBAL__I.", sizeof ("GLOBAL__I.")-1, SYM_CTOR, 0 },
+    { "GLOBAL__D.", sizeof ("GLOBAL__D.")-1, SYM_DTOR, 0 },
 #endif /* NO_DOT_IN_LABEL */
 #endif /* NO_DOLLAR_IN_LABEL */
-    { "GLOBAL__I_", sizeof ("GLOBAL__I_")-1, 1, 0 },
-    { "GLOBAL__D_", sizeof ("GLOBAL__D_")-1, 2, 0 },
-    { "GLOBAL__F_", sizeof ("GLOBAL__F_")-1, 5, 0 },
-    { "GLOBAL__FI_", sizeof ("GLOBAL__FI_")-1, 3, 0 },
-    { "GLOBAL__FD_", sizeof ("GLOBAL__FD_")-1, 4, 0 },
-    { NULL, 0, 0, 0 }
+    { "GLOBAL__I_", sizeof ("GLOBAL__I_")-1, SYM_CTOR, 0 },
+    { "GLOBAL__D_", sizeof ("GLOBAL__D_")-1, SYM_DTOR, 0 },
+    { "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 },
+    { NULL, 0, SYM_REGULAR, 0 }
   };
 
   while ((ch = *s) == '_')
     ++s;
 
   if (s == orig_s)
-    return 0;
+    return SYM_REGULAR;
 
   for (p = &special[0]; p->len > 0; p++)
     {
@@ -545,7 +634,7 @@ is_ctor_dtor (const char *s)
          return p->ret;
        }
     }
-  return 0;
+  return SYM_REGULAR;
 }
 \f
 /* We maintain two prefix lists: one from COMPILER_PATH environment variable
@@ -583,11 +672,7 @@ find_a_file (struct path_prefix *pprefix, const char *name)
 
   /* Determine the filename to execute (special case for absolute paths).  */
 
-  if (*name == '/'
-#ifdef HAVE_DOS_BASED_FILE_SYSTEM
-      || (*name && name[1] == ':')
-#endif
-      )
+  if (IS_ABSOLUTE_PATH (name))
     {
       if (access (name, X_OK) == 0)
        {
@@ -728,6 +813,7 @@ prefix_from_string (const char *p, struct path_prefix *pprefix)
       else
        endp++;
     }
+  free (nstore);
 }
 \f
 /* Main program.  */
@@ -788,12 +874,29 @@ main (int argc, char **argv)
   const char **c_ptr;
   char **ld1_argv;
   const char **ld1;
+  
+  /* 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
+     be adjusted before getting to the first pass link per se, typically on
+     AIX where we perform an early scan of objects and libraries to fetch
+     the list of global ctors/dtors and make sure they are not garbage
+     collected.  */
+  scanfilter ld1_filter = SCAN_ALL;
+
   char **ld2_argv;
   const char **ld2;
   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");
 
@@ -819,9 +922,12 @@ main (int argc, char **argv)
   /* 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+4));
-  ld2 = (const char **)(ld2_argv = xcalloc(sizeof (char *), argc+11));
-  object = (const char **)(object_lst = xcalloc(sizeof (char *), argc));
+  ld1_argv = XCNEWVEC (char *, argc + 4);
+  ld1 = CONST_CAST2 (const char **, char **, ld1_argv);
+  ld2_argv = XCNEWVEC (char *, argc + 11);
+  ld2 = CONST_CAST2 (const char **, char **, ld2_argv);
+  object_lst = XCNEWVEC (char *, argc);
+  object = CONST_CAST2 (const char **, char **, object_lst);
 
 #ifdef DEBUG
   debug = 1;
@@ -848,7 +954,7 @@ main (int argc, char **argv)
 #endif
 
   obstack_begin (&temporary_obstack, 0);
-  temporary_firstobj = obstack_alloc (&temporary_obstack, 0);
+  temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0);
 
 #ifndef HAVE_LD_DEMANGLE
   current_demangling_style = auto_demangling;
@@ -866,7 +972,8 @@ main (int argc, char **argv)
      -fno-exceptions -w */
   num_c_args += 5;
 
-  c_ptr = (const char **) (c_argv = xcalloc (sizeof (char *), num_c_args));
+  c_argv = XCNEWVEC (char *, num_c_args);
+  c_ptr = CONST_CAST2 (const char **, char **, c_argv);
 
   if (argc < 2)
     fatal ("no arguments");
@@ -1112,7 +1219,9 @@ main (int argc, char **argv)
 #else
 #if LINK_ELIMINATE_DUPLICATE_LDIRECTORIES
            case 'L':
-             if (is_in_args (arg, (const char **) ld1_argv, ld1-1))
+             if (is_in_args (arg,
+                             CONST_CAST2 (const char **, char **, ld1_argv),
+                             ld1 - 1))
                --ld1;
              break;
 #endif /* LINK_ELIMINATE_DUPLICATE_LDIRECTORIES */
@@ -1177,6 +1286,8 @@ main (int argc, char **argv)
                  ld1--;
                  ld2--;
                }
+             else if (strncmp (arg, "--sysroot=", 10) == 0)
+               target_system_root = arg + 10;
              break;
            }
        }
@@ -1220,18 +1331,31 @@ main (int argc, char **argv)
     }
 
   /* The AIX linker will discard static constructors in object files if
-     nothing else in the file is referenced, so look at them first.  */
-  {
-      const char **export_object_lst = (const char **)object_lst;
-
-      while (export_object_lst < object)
-       scan_prog_file (*export_object_lst++, PASS_OBJ);
-  }
+     nothing else in the file is referenced, so look at them first.  Unless
+     we are building a shared object, ignore the eh frame tables, as we
+     would otherwise reference them all, hence drag all the corresponding
+     objects even if nothing else is referenced.  */
   {
+    const char **export_object_lst 
+      = CONST_CAST2 (const char **, char **, object_lst);
+    
     struct id *list = libs.first;
 
+    /* Compute the filter to use from the current one, do scan, then adjust
+       the "current" filter to remove what we just included here.  This will
+       control whether we need a first pass link later on or not, and what
+       will remain to be scanned there.  */
+    
+    scanfilter this_filter
+      = shared_obj ? ld1_filter : (ld1_filter & ~SCAN_DWEH);
+    
+    while (export_object_lst < object)
+      scan_prog_file (*export_object_lst++, PASS_OBJ, this_filter);
+    
     for (; list; list = list->next)
-      scan_prog_file (list->name, PASS_FIRST);
+      scan_prog_file (list->name, PASS_FIRST, this_filter);
+    
+    ld1_filter = ld1_filter & ~this_filter;
   }
 
   if (exports.first)
@@ -1302,42 +1426,45 @@ main (int argc, char **argv)
     }
 
   /* Load the program, searching all libraries and attempting to provide
-     undefined symbols from repository information.  */
-
-  /* On AIX we do this later.  */
-#ifndef COLLECT_EXPORT_LIST
-  do_tlink (ld1_argv, object_lst);
-#endif
-
-  /* If -r or they will be run via some other method, do not build the
-     constructor or destructor list, just return now.  */
-  if (rflag
-#ifndef COLLECT_EXPORT_LIST
-      || ! do_collecting
-#endif
-      )
-    {
-#ifdef COLLECT_EXPORT_LIST
-      /* Do the link we avoided above if we are exiting.  */
+     undefined symbols from repository information.
+     
+     If -r or they will be run via some other method, do not build the
+     constructor or destructor list, just return now.  */  
+  {
+    bool early_exit
+      = rflag || (! DO_COLLECT_EXPORT_LIST && ! do_collecting);
+
+    /* Perform the first pass link now, if we're about to exit or if we need
+       to scan for things we haven't collected yet before pursuing further.
+
+       On AIX, the latter typically includes nothing for shared objects or
+       frame tables for an executable, out of what the required early scan on
+       objects and libraries has performed above.  In the !shared_obj case, we
+       expect the relevant tables to be dragged together with their associated
+       functions from precise cross reference insertions by the compiler.  */
+       
+    if (early_exit || ld1_filter != SCAN_NOTHING)
       do_tlink (ld1_argv, object_lst);
-
-      /* But make sure we delete the export file we may have created.  */
-      if (export_file != 0 && export_file[0])
-       maybe_unlink (export_file);
+    
+    if (early_exit)
+      {
+#ifdef COLLECT_EXPORT_LIST
+       /* Make sure we delete the export file we may have created.  */
+       if (export_file != 0 && export_file[0])
+         maybe_unlink (export_file);
 #endif
-      maybe_unlink (c_file);
-      maybe_unlink (o_file);
-      return 0;
-    }
+       maybe_unlink (c_file);
+       maybe_unlink (o_file);
+       return 0;
+      }
+  }
 
-  /* Examine the namelist with nm and search it for static constructors
-     and destructors to call.
-     Write the constructor and destructor tables to a .s file and reload.  */
+  /* Unless we have done it all already, examine the namelist and search for
+     static constructors and destructors to call.  Write the constructor and
+     destructor tables to a .s file and reload.  */
 
-  /* On AIX we already scanned for global constructors/destructors.  */
-#ifndef COLLECT_EXPORT_LIST
-  scan_prog_file (output_file, PASS_FIRST);
-#endif
+  if (ld1_filter != SCAN_NOTHING)
+    scan_prog_file (output_file, PASS_FIRST, ld1_filter);
 
 #ifdef SCAN_LIBRARIES
   scan_libraries (output_file);
@@ -1350,6 +1477,9 @@ main (int argc, char **argv)
       notice ("%d frame table(s) found\n", frame_tables.number);
     }
 
+  /* If the scan exposed nothing of special interest, there's no need to
+     generate the glue code and relink so return now.  */
+
   if (constructors.number == 0 && destructors.number == 0
       && frame_tables.number == 0
 #if defined (SCAN_LIBRARIES) || defined (COLLECT_EXPORT_LIST)
@@ -1360,15 +1490,17 @@ main (int argc, char **argv)
 #endif
       )
     {
-#ifdef COLLECT_EXPORT_LIST
-      /* Do tlink without additional code generation.  */
-      do_tlink (ld1_argv, object_lst);
-#endif
+      /* Do tlink without additional code generation now if we didn't
+        do it earlier for scanning purposes.  */
+      if (ld1_filter == SCAN_NOTHING)
+       do_tlink (ld1_argv, object_lst);
+
       /* Strip now if it was requested on the command line.  */
       if (strip_flag)
        {
          char **real_strip_argv = XCNEWVEC (char *, 3);
-         const char ** strip_argv = (const char **) real_strip_argv;
+         const char ** strip_argv = CONST_CAST2 (const char **, char **,
+                                                 real_strip_argv);
 
          strip_argv[0] = strip_file_name;
          strip_argv[1] = output_file;
@@ -1462,7 +1594,7 @@ main (int argc, char **argv)
 
   /* Let scan_prog_file do any final mods (OSF/rose needs this for
      constructors/destructors in shared libraries.  */
-  scan_prog_file (output_file, PASS_SECOND);
+  scan_prog_file (output_file, PASS_SECOND, SCAN_ALL);
 #endif
 
   maybe_unlink (c_file);
@@ -1513,6 +1645,12 @@ do_wait (const char *prog, struct pex_obj *pex)
       error ("%s returned %d exit status", prog, ret);
       collect_exit (ret);
     }
+
+  if (response_file)
+    {
+      unlink (response_file);
+      response_file = NULL;
+    }
 }
 
 \f
@@ -1525,6 +1663,47 @@ collect_execute (const char *prog, char **argv, const char *outname,
   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)
     {
@@ -1568,6 +1747,9 @@ collect_execute (const char *prog, char **argv, const char *outname,
        fatal (errmsg);
     }
 
+  if (response_arg)
+    free (response_arg);
+
   return pex;
 }
 
@@ -1599,7 +1781,8 @@ static long sequence_number = 0;
 static void
 add_to_list (struct head *head_ptr, const char *name)
 {
-  struct id *newid = xcalloc (sizeof (struct id) + strlen (name), 1);
+  struct id *newid
+    = (struct id *) xcalloc (sizeof (struct id) + strlen (name), 1);
   struct id *p;
   strcpy (newid->name, name);
 
@@ -1791,9 +1974,9 @@ write_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED)
        }
       else
        {
-         if (strncmp (q, ".so", 3) == 0)
+         if (strncmp (q, SHLIB_SUFFIX, strlen (SHLIB_SUFFIX)) == 0)
            {
-             q += 3;
+             q += strlen (SHLIB_SUFFIX);
              break;
            }
          else
@@ -1962,14 +2145,12 @@ write_c_file_glob (FILE *stream, const char *name ATTRIBUTE_UNUSED)
 static void
 write_c_file (FILE *stream, const char *name)
 {
-  fprintf (stream, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
 #ifndef LD_INIT_SWITCH
   if (! shared_obj)
     write_c_file_glob (stream, name);
   else
 #endif
     write_c_file_stat (stream, name);
-  fprintf (stream, "#ifdef __cplusplus\n}\n#endif\n");
 }
 
 #ifdef COLLECT_EXPORT_LIST
@@ -1987,23 +2168,18 @@ write_aix_file (FILE *stream, struct id *list)
 #ifdef OBJECT_FORMAT_NONE
 
 /* Generic version to scan the name list of the loaded program for
-   the symbols g++ uses for static constructors and destructors.
-
-   The constructor table begins at __CTOR_LIST__ and contains a count
-   of the number of pointers (or -1 if the constructors are built in a
-   separate section by the linker), followed by the pointers to the
-   constructor functions, terminated with a null pointer.  The
-   destructor table has the same format, and begins at __DTOR_LIST__.  */
+   the symbols g++ uses for static constructors and destructors.  */
 
 static void
-scan_prog_file (const char *prog_name, enum pass which_pass)
+scan_prog_file (const char *prog_name, scanpass which_pass,
+               scanfilter filter)
 {
   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;
+  const char **nm_argv = CONST_CAST2 (const char **, char**, real_nm_argv);
   int argc = 0;
   struct pex_obj *pex;
   const char *errmsg;
@@ -2075,7 +2251,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
       char *name, *end;
 
       /* If it contains a constructor or destructor name, add the name
-        to the appropriate list.  */
+        to the appropriate list unless this is a kind of symbol we're
+        not supposed to even consider.  */
 
       for (p = buf; (ch = *p) != '\0' && ch != '\n' && ch != '_'; p++)
        if (ch == ' ' && p[1] == 'U' && p[2] == ' ')
@@ -2095,17 +2272,23 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
       *end = '\0';
       switch (is_ctor_dtor (name))
        {
-       case 1:
+       case SYM_CTOR:
+         if (! (filter & SCAN_CTOR))
+           break;
          if (which_pass != PASS_LIB)
            add_to_list (&constructors, name);
          break;
 
-       case 2:
+       case SYM_DTOR:
+         if (! (filter & SCAN_DTOR))
+           break;
          if (which_pass != PASS_LIB)
            add_to_list (&destructors, name);
          break;
 
-       case 3:
+       case SYM_INIT:
+         if (! (filter & SCAN_INIT))
+           break;
          if (which_pass != PASS_LIB)
            fatal ("init function found in object %s", prog_name);
 #ifndef LD_INIT_SWITCH
@@ -2113,7 +2296,9 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
 #endif
          break;
 
-       case 4:
+       case SYM_FINI:
+         if (! (filter & SCAN_FINI))
+           break;
          if (which_pass != PASS_LIB)
            fatal ("fini function found in object %s", prog_name);
 #ifndef LD_FINI_SWITCH
@@ -2121,7 +2306,9 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
 #endif
          break;
 
-       case 5:
+       case SYM_DWEH:
+         if (! (filter & SCAN_DWEH))
+           break;
          if (which_pass != PASS_LIB)
            add_to_list (&frame_tables, name);
          break;
@@ -2161,7 +2348,7 @@ scan_libraries (const char *prog_name)
   void (*quit_handler) (int);
 #endif
   char *real_ldd_argv[4];
-  const char **ldd_argv = (const char **) real_ldd_argv;
+  const char **ldd_argv = CONST_CAST2 (const char **, char **, real_ldd_argv);
   int argc = 0;
   struct pex_obj *pex;
   const char *errmsg;
@@ -2317,7 +2504,7 @@ scan_libraries (const char *prog_name)
 #   define GCC_SYMZERO(X)      0
 
 /* 0757 = U803XTOCMAGIC (AIX 4.3) and 0767 = U64_TOCMAGIC (AIX V5) */
-#ifdef _AIX51
+#if TARGET_AIX_VERSION >= 51
 #   define GCC_CHECK_HDR(X) \
      ((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \
       || (HEADER (X).f_magic == 0767 && aix64_flag))
@@ -2356,9 +2543,19 @@ static int ignore_library (const char *);
 static int
 ignore_library (const char *name)
 {
-  const char *const *p = &aix_std_libs[0];
-  while (*p++ != NULL)
-    if (! strcmp (name, *p)) return 1;
+  const char *const *p;
+  size_t length;
+
+  if (target_system_root[0] != '\0')
+    {
+      length = strlen (target_system_root);
+      if (strncmp (name, target_system_root, length) != 0)
+       return 0;
+      name += length;
+    }
+  for (p = &aix_std_libs[0]; *p != NULL; ++p)
+    if (strcmp (name, *p) == 0)
+      return 1;
   return 0;
 }
 #endif /* COLLECT_EXPORT_LIST */
@@ -2368,16 +2565,11 @@ extern char *ldgetname (LDFILE *, GCC_SYMENT *);
 #endif
 
 /* COFF version to scan the name list of the loaded program for
-   the symbols g++ uses for static constructors and destructors.
-
-   The constructor table begins at __CTOR_LIST__ and contains a count
-   of the number of pointers (or -1 if the constructors are built in a
-   separate section by the linker), followed by the pointers to the
-   constructor functions, terminated with a null pointer.  The
-   destructor table has the same format, and begins at __DTOR_LIST__.  */
+   the symbols g++ uses for static constructors and destructors.  */
 
 static void
-scan_prog_file (const char *prog_name, enum pass which_pass)
+scan_prog_file (const char *prog_name, scanpass which_pass,
+               scanfilter filter)
 {
   LDFILE *ldptr = NULL;
   int sym_index, sym_count;
@@ -2400,8 +2592,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
       /* 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.  */
-      if ((ldptr = ldopen ((char *)prog_name, ldptr)) != NULL)
+        using CONST_CAST to prevent complaints from -Wcast-qual.  */
+      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);
@@ -2440,7 +2632,9 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
 
                      switch (is_ctor_dtor (name))
                        {
-                       case 1:
+                       case SYM_CTOR:
+                         if (! (filter & SCAN_CTOR))
+                           break;
                          if (! is_shared)
                            add_to_list (&constructors, name);
 #if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
@@ -2449,7 +2643,9 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
 #endif
                          break;
 
-                       case 2:
+                       case SYM_DTOR:
+                         if (! (filter & SCAN_DTOR))
+                           break;
                          if (! is_shared)
                            add_to_list (&destructors, name);
 #if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
@@ -2459,14 +2655,18 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
                          break;
 
 #ifdef COLLECT_EXPORT_LIST
-                       case 3:
+                       case SYM_INIT:
+                         if (! (filter & SCAN_INIT))
+                           break;
 #ifndef LD_INIT_SWITCH
                          if (is_shared)
                            add_to_list (&constructors, name);
 #endif
                          break;
 
-                       case 4:
+                       case SYM_FINI:
+                         if (! (filter & SCAN_FINI))
+                           break;
 #ifndef LD_INIT_SWITCH
                          if (is_shared)
                            add_to_list (&destructors, name);
@@ -2474,7 +2674,9 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
                          break;
 #endif
 
-                       case 5:
+                       case SYM_DWEH:
+                         if (! (filter & SCAN_DWEH))
+                           break;
                          if (! is_shared)
                            add_to_list (&frame_tables, name);
 #if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
@@ -2552,7 +2754,7 @@ resolve_lib_name (const char *name)
     if (libpaths[i]->max_len > l)
       l = libpaths[i]->max_len;
 
-  lib_buf = xmalloc (l + strlen(name) + 10);
+  lib_buf = XNEWVEC (char, l + strlen(name) + 10);
 
   for (i = 0; libpaths[i]; i++)
     {