OSDN Git Service

Fix mips64vr4100-elf build failure.
[pf3gnuchains/gcc-fork.git] / gcc / collect2.c
index d311b66..eec7a95 100644 (file)
@@ -1,10 +1,8 @@
-/* Collect static initialization info into data structures
-   that can be traversed by C++ initialization and finalization
-   routines.
-
-   Copyright (C) 1992 Free Software Foundation, Inc.
+/* Collect static initialization info into data structures that can be
+   traversed by C++ initialization and finalization routines.
+   Copyright (C) 1992, 93-97, 1998 Free Software Foundation, Inc.
    Contributed by Chris Smith (csmith@convex.com).
-   Heavily modified by Michael Meissner (meissner@osf.org),
+   Heavily modified by Michael Meissner (meissner@cygnus.com),
    Per Bothner (bothner@cygnus.com), and John Gilmore (gnu@cygnus.com).
 
 This file is part of GNU CC.
@@ -21,63 +19,64 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
-/* Build tables of static constructors and destructors and run ld. */
+/* Build tables of static constructors and destructors and run ld.  */
 
-#include <sys/types.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <errno.h>
+#include "config.h"
+#include "system.h"
 #include <signal.h>
-#include <sys/file.h>
 #include <sys/stat.h>
-#ifdef NO_WAIT_H
-#include <sys/wait.h>
-#endif
-
-#ifndef errno
-extern int errno;
-#endif
 
 #define COLLECT
 
-#include "config.h"
-
-#ifndef __STDC__
-#define generic char
-#define const
+#include "demangle.h"
+#include "obstack.h"
+#include "gansidecl.h"
+#ifdef __CYGWIN32__
+#include <process.h>
+#endif
 
+#ifndef HAVE_STRERROR
+extern char *sys_errlist[];
+extern int sys_nerr;
 #else
-#define generic void
+char *strerror();
 #endif
 
+/* Obstack allocation and deallocation routines.  */
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
 #ifdef USG
 #define vfork fork
 #endif
 
-#ifndef R_OK
-#define R_OK 4
-#define W_OK 2
-#define X_OK 1
+#ifndef WIFSIGNALED
+#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
 #endif
-
-/* On MSDOS, write temp files in current dir
-   because there's no place else we can expect to use.  */
-#if __MSDOS__
-#ifndef P_tmpdir
-#define P_tmpdir "./"
+#ifndef WTERMSIG
+#define WTERMSIG(S) ((S) & 0x7f)
 #endif
+#ifndef WIFEXITED
+#define WIFEXITED(S) (((S) & 0xff) == 0)
 #endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
+#endif
+
+extern char *choose_temp_base ();
 \f
 /* On certain systems, we have code that works by scanning the object file
    directly.  But this code uses system-specific header files and library
    functions, so turn it off in a cross-compiler.  Likewise, the names of
-   the utilities aren't correct for a cross-compiler; we have to hope that
+   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
 #undef OBJECT_FORMAT_COFF
 #undef OBJECT_FORMAT_ROSE
 #undef MD_EXEC_PREFIX
@@ -86,10 +85,10 @@ extern int errno;
 #undef REAL_STRIP_FILE_NAME
 #endif
 
-/* If we can't use a special method, use the ordinary one:
+/* If we cannot use a special method, use the ordinary one:
    run nm to find what symbols are present.
    In a cross-compiler, this means you need a cross nm,
-   but that isn't quite as unpleasant as special headers.  */
+   but that is not quite as unpleasant as special headers.  */
 
 #if !defined (OBJECT_FORMAT_COFF) && !defined (OBJECT_FORMAT_ROSE)
 #define OBJECT_FORMAT_NONE
@@ -149,8 +148,27 @@ extern int errno;
 #endif
 
 #endif /* OBJECT_FORMAT_NONE */
+
+/* Some systems use __main in a way incompatible with its use in gcc, in these
+   cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
+   give the same symbol without quotes for an alternative entry point.  You
+   must define both, or neither.  */
+#ifndef NAME__MAIN
+#define NAME__MAIN "__main"
+#define SYMBOL__MAIN __main
+#endif
+
+#if defined (LDD_SUFFIX) || SUNOS4_SHARED_LIBRARIES
+#define SCAN_LIBRARIES
+#endif
+
+#ifdef USE_COLLECT2
+int do_collecting = 1;
+#else
+int do_collecting = 0;
+#endif
 \f
-/* Linked lists of constructor and destructor names. */
+/* Linked lists of constructor and destructor names.  */
 
 struct id 
 {
@@ -170,50 +188,134 @@ struct head
 
 enum pass {
   PASS_FIRST,                          /* without constructors */
+  PASS_OBJ,                            /* individual objects */
+  PASS_LIB,                            /* looking for shared libraries */
   PASS_SECOND                          /* with constructors linked in */
 };
 
 #ifndef NO_SYS_SIGLIST
+#ifndef SYS_SIGLIST_DECLARED
 extern char *sys_siglist[];
 #endif
+#endif
 extern char *version_string;
 
-static int vflag;                      /* true if -v */
+int vflag;                             /* true if -v */
 static int rflag;                      /* true if -r */
 static int strip_flag;                 /* true if -s */
+#ifdef COLLECT_EXPORT_LIST
+static int export_flag;                 /* true if -bE */
+#endif
+
+int debug;                             /* true if -debug */
 
-static int debug;                      /* true if -debug */
+static int shared_obj;                 /* true if -shared */
 
 static int   temp_filename_length;     /* Length of temp_filename */
 static char *temp_filename;            /* Base of temp filenames */
-static char *c_file;                   /* <xxx>.c for constructor/destructor list. */
-static char *o_file;                   /* <xxx>.o for constructor/destructor list. */
+static char *c_file;                   /* <xxx>.c for constructor/destructor list.  */
+static char *o_file;                   /* <xxx>.o for constructor/destructor list.  */
+#ifdef COLLECT_EXPORT_LIST
+static char *export_file;              /* <xxx>.x for AIX export list.  */
+static char *import_file;              /* <xxx>.p for AIX import list.  */
+#endif
+char *ldout;                           /* File for ld errors.  */
 static char *output_file;              /* Output file for ld.  */
 static char *nm_file_name;             /* pathname of nm */
+#ifdef LDD_SUFFIX
+static char *ldd_file_name;            /* pathname of ldd (or equivalent) */
+#endif
 static char *strip_file_name;          /* pathname of strip */
+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 */
 static struct head destructors;                /* list of destructors found */
+#ifdef COLLECT_EXPORT_LIST
+static struct head exports;            /* list of exported symbols */
+static struct head imports;            /* list of imported symbols */
+static struct head undefined;          /* list of undefined symbols */
+#endif
+static struct head frame_tables;       /* list of frame unwind info tables */
+
+struct obstack temporary_obstack;
+struct obstack permanent_obstack;
+char * temporary_firstobj;
+
+/* Defined in the automatically-generated underscore.c.  */
+extern int prepends_underscore;
 
-extern char *getenv ();
 extern char *mktemp ();
-static void  add_to_list ();
-static void  scan_prog_file ();
-static void  fork_execute ();
-static void  do_wait ();
-static void  write_c_file ();
-static void  my_exit ();
-static void  handler ();
-static void  maybe_unlink ();
-static void  choose_temp_base ();
-
-generic *xcalloc ();
-generic *xmalloc ();
-
-extern char *index ();
-extern char *rindex ();
+extern FILE *fdopen ();
+
+#ifndef GET_ENVIRONMENT
+#define GET_ENVIRONMENT(ENV_VALUE,ENV_NAME) ENV_VALUE = getenv (ENV_NAME)
+#endif
+
+/* Structure to hold all the directories in which to search for files to
+   execute.  */
+
+struct prefix_list
+{
+  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 */
+  char *name;                 /* Name of this list (used in config stuff) */
+};
+
+#ifdef COLLECT_EXPORT_LIST
+/* Lists to keep libraries to be scanned for global constructors/destructors. */
+static struct head libs;                    /* list of libraries */
+static struct path_prefix cmdline_lib_dirs; /* directories specified with -L */
+static struct path_prefix libpath_lib_dirs; /* directories in LIBPATH */
+static struct path_prefix *libpaths[3] = {&cmdline_lib_dirs,
+                                         &libpath_lib_dirs, NULL};
+static char *libexts[3] = {"a", "so", NULL};  /* possible library extentions */
+#endif
+
+static void handler            PROTO((int));
+static int is_ctor_dtor                PROTO((char *));
+static char *find_a_file       PROTO((struct path_prefix *, char *));
+static void add_prefix         PROTO((struct path_prefix *, char *));
+static void prefix_from_env    PROTO((char *, struct path_prefix *));
+static void prefix_from_string PROTO((char *, struct path_prefix *));
+static void do_wait            PROTO((char *));
+static void fork_execute       PROTO((char *, char **));
+static void maybe_unlink       PROTO((char *));
+static void add_to_list                PROTO((struct head *, char *));
+static void write_list         PROTO((FILE *, char *, struct id *));
+#ifdef COLLECT_EXPORT_LIST
+static void dump_list          PROTO((FILE *, char *, struct id *));
+#endif
+#if 0
+static void dump_prefix_list   PROTO((FILE *, char *, struct prefix_list *));
+#endif
+static void write_list_with_asm PROTO((FILE *, char *, struct id *));
+static void write_c_file       PROTO((FILE *, char *));
+static void scan_prog_file     PROTO((char *, enum pass));
+#ifdef SCAN_LIBRARIES
+static void scan_libraries     PROTO((char *));
+#endif
+#ifdef COLLECT_EXPORT_LIST
+static int is_in_list          PROTO((char *, struct id *));
+static void write_export_file  PROTO((FILE *));
+static void write_import_file  PROTO((FILE *));
+static char *resolve_lib_name  PROTO((char *));
+static int use_import_list     PROTO((char *));
+static int ignore_library      PROTO((char *));
+#endif
+
+char *xcalloc ();
+char *xmalloc ();
+
 \f
 #ifdef NO_DUP2
+int
 dup2 (oldfd, newfd)
      int oldfd;
      int newfd;
@@ -223,12 +325,14 @@ dup2 (oldfd, newfd)
   int fd;
  
   if (oldfd == newfd)
-    return 0;
+    return oldfd;
   close (newfd);
-  while ((fd = dup (oldfd)) != newfd) /* good enough for low fd's */
+  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
 
@@ -236,10 +340,13 @@ char *
 my_strerror (e)
      int e;
 {
-  extern char *sys_errlist[];
-  extern int sys_nerr;
-  static char buffer[30];
 
+#ifdef HAVE_STRERROR
+  return strerror (e);
+
+#else
+
+  static char buffer[30];
   if (!e)
     return "";
 
@@ -248,12 +355,13 @@ my_strerror (e)
 
   sprintf (buffer, "Unknown error %d", e);
   return buffer;
+#endif
 }
 \f
 /* Delete tempfiles and exit function.  */
 
-static void
-my_exit (status)
+void
+collect_exit (status)
      int status;
 {
   if (c_file != 0 && c_file[0])
@@ -262,6 +370,20 @@ my_exit (status)
   if (o_file != 0 && o_file[0])
     maybe_unlink (o_file);
 
+#ifdef COLLECT_EXPORT_LIST
+  if (export_file != 0 && export_file[0])
+    maybe_unlink (export_file);
+
+  if (import_file != 0 && import_file[0])
+    maybe_unlink (import_file);
+#endif
+
+  if (ldout != 0 && ldout[0])
+    {
+      dump_file (ldout);
+      maybe_unlink (ldout);
+    }
+
   if (status != 0 && output_file != 0 && output_file[0])
     maybe_unlink (output_file);
 
@@ -269,39 +391,39 @@ my_exit (status)
 }
 
 \f
-/* Die when sys call fails. */
+/* Die when sys call fails.  */
 
-static void
+void
 fatal_perror (string, arg1, arg2, arg3)
-     char *string;
+     char *string, *arg1, *arg2, *arg3;
 {
   int e = errno;
 
-  fprintf (stderr, "collect: ");
+  fprintf (stderr, "collect2: ");
   fprintf (stderr, string, arg1, arg2, arg3);
   fprintf (stderr, ": %s\n", my_strerror (e));
-  my_exit (1);
+  collect_exit (FATAL_EXIT_CODE);
 }
 
-/* Just die. */
+/* Just die.  */
 
-static void
+void
 fatal (string, arg1, arg2, arg3)
-     char *string;
+     char *string, *arg1, *arg2, *arg3;
 {
-  fprintf (stderr, "collect: ");
+  fprintf (stderr, "collect2: ");
   fprintf (stderr, string, arg1, arg2, arg3);
   fprintf (stderr, "\n");
-  my_exit (1);
+  collect_exit (FATAL_EXIT_CODE);
 }
 
 /* Write error message.  */
 
-static void
+void
 error (string, arg1, arg2, arg3, arg4)
-     char *string;
+     char *string, *arg1, *arg2, *arg3, *arg4;
 {
-  fprintf (stderr, "collect: ");
+  fprintf (stderr, "collect2: ");
   fprintf (stderr, string, arg1, arg2, arg3, arg4);
   fprintf (stderr, "\n");
 }
@@ -320,39 +442,68 @@ static void
 handler (signo)
      int signo;
 {
-  if (c_file[0])
+  if (c_file != 0 && c_file[0])
     maybe_unlink (c_file);
 
-  if (o_file[0])
+  if (o_file != 0 && o_file[0])
     maybe_unlink (o_file);
 
+  if (ldout != 0 && ldout[0])
+    maybe_unlink (ldout);
+
+#ifdef COLLECT_EXPORT_LIST
+  if (export_file != 0 && export_file[0])
+    maybe_unlink (export_file);
+
+  if (import_file != 0 && import_file[0])
+    maybe_unlink (import_file);
+#endif
+
   signal (signo, SIG_DFL);
   kill (getpid (), signo);
 }
 
 \f
-generic *
+char *
 xcalloc (size1, size2)
      int size1, size2;
 {
-  generic *ptr = (generic *) calloc (size1, size2);
+  char *ptr = (char *) calloc (size1, size2);
   if (ptr)
     return ptr;
 
   fatal ("out of memory");
-  return (generic *)0;
+  return (char *) 0;
 }
 
-generic *
+char *
 xmalloc (size)
-     int size;
+     unsigned size;
 {
-  generic *ptr = (generic *) malloc (size);
+  char *ptr = (char *) malloc (size);
   if (ptr)
     return ptr;
 
   fatal ("out of memory");
-  return (generic *)0;
+  return (char *) 0;
+}
+
+char *
+xrealloc (ptr, size)
+     char *ptr;
+     unsigned size;
+{
+  register char *value = (char *) realloc (ptr, size);
+  if (value == 0)
+    fatal ("virtual memory exhausted");
+  return value;
+}
+
+int
+file_exists (name)
+     char *name;
+{
+  return access (name, R_OK) == 0;
 }
 
 /* Make a copy of a string INPUT with size SIZE.  */
@@ -367,6 +518,97 @@ savestring (input, size)
   output[size] = 0;
   return output;
 }
+
+/* Parse a reasonable subset of shell quoting syntax.  */
+
+static char *
+extract_string (pp)
+     char **pp;
+{
+  char *p = *pp;
+  int backquote = 0;
+  int inside = 0;
+
+  for (;;)
+    {
+      char c = *p;
+      if (c == '\0')
+       break;
+      ++p;
+      if (backquote)
+       obstack_1grow (&temporary_obstack, c);
+      else if (! inside && c == ' ')
+       break;
+      else if (! inside && c == '\\')
+       backquote = 1;
+      else if (c == '\'')
+       inside = !inside;
+      else
+       obstack_1grow (&temporary_obstack, c);
+    }
+
+  obstack_1grow (&temporary_obstack, '\0');
+  *pp = p;
+  return obstack_finish (&temporary_obstack);
+}
+\f
+void
+dump_file (name)
+     char *name;
+{
+  FILE *stream = fopen (name, "r");
+  int no_demangle = !! getenv ("COLLECT_NO_DEMANGLE");
+
+  if (stream == 0)
+    return;
+  while (1)
+    {
+      int c;
+      while (c = getc (stream),
+            c != EOF && (ISALNUM (c) || c == '_' || c == '$' || c == '.'))
+       obstack_1grow (&temporary_obstack, c);
+      if (obstack_object_size (&temporary_obstack) > 0)
+       {
+         char *word, *p, *result;
+         obstack_1grow (&temporary_obstack, '\0');
+         word = obstack_finish (&temporary_obstack);
+
+         if (*word == '.')
+           ++word, putc ('.', stderr);
+         p = word;
+         if (*p == '_' && prepends_underscore)
+           ++p;
+
+         if (no_demangle)
+           result = 0;
+         else
+           result = cplus_demangle (p, DMGL_PARAMS | DMGL_ANSI);
+
+         if (result)
+           {
+             int diff;
+             fputs (result, stderr);
+
+             diff = strlen (word) - strlen (result);
+             while (diff > 0)
+               --diff, putc (' ', stderr);
+             while (diff < 0 && c == ' ')
+               ++diff, c = getc (stream);
+
+             free (result);
+           }
+         else
+           fputs (word, stderr);
+
+         fflush (stderr);
+         obstack_free (&temporary_obstack, temporary_firstobj);
+       }
+      if (c == EOF)
+       break;
+      putc (c, stderr);
+    }
+  fclose (stream);
+}
 \f
 /* Decide whether the given symbol is:
    a constructor (1), a destructor (2), or neither (0).  */
@@ -384,17 +626,22 @@ is_ctor_dtor (s)
   static struct names special[] = {
 #ifdef NO_DOLLAR_IN_LABEL
 #ifdef 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, 1, 0 },
+    { "GLOBAL__D_", sizeof ("GLOBAL__D_")-1, 2, 0 },
+    { "GLOBAL__F_", sizeof ("GLOBAL__F_")-1, 5, 0 },
 #else
     { "GLOBAL_.I.", sizeof ("GLOBAL_.I.")-1, 1, 0 },
     { "GLOBAL_.D.", sizeof ("GLOBAL_.D.")-1, 2, 0 },
+    { "GLOBAL_.F.", sizeof ("GLOBAL_.F.")-1, 5, 0 },
 #endif
 #else
     { "GLOBAL_$I$", sizeof ("GLOBAL_$I$")-1, 1, 0 },
-    { "GLOBAL_$D$", sizeof ("GLOBAL_$I$")-1, 2, 0 },
+    { "GLOBAL_$D$", sizeof ("GLOBAL_$D$")-1, 2, 0 },
+    { "GLOBAL_$F$", sizeof ("GLOBAL_$F$")-1, 5, 0 },
 #endif
-#ifdef CFRONT_LOSSAGE /* Don't collect cfront initialization functions.
+    { "GLOBAL__FI_", sizeof ("GLOBAL__FI_")-1, 3, 0 },
+    { "GLOBAL__FD_", sizeof ("GLOBAL__FD_")-1, 4, 0 },
+#ifdef CFRONT_LOSSAGE /* Do not collect cfront initialization functions.
                         cfront has its own linker procedure to collect them;
                         if collect2 gets them too, they get collected twice
                         when the cfront procedure is run and the compiler used
@@ -422,47 +669,12 @@ is_ctor_dtor (s)
     }
   return 0;
 }
-
-\f
-/* Compute a string to use as the base of all temporary file names.
-   It is substituted for %g.  */
-
-static void
-choose_temp_base ()
-{
-  char *base = getenv ("TMPDIR");
-  int len;
-
-  if (base == (char *)0)
-    {
-#ifdef P_tmpdir
-      if (access (P_tmpdir, R_OK | W_OK) == 0)
-       base = P_tmpdir;
-#endif
-      if (base == (char *)0)
-       {
-         if (access ("/usr/tmp", R_OK | W_OK) == 0)
-           base = "/usr/tmp/";
-         else
-           base = "/tmp/";
-       }
-    }
-
-  len = strlen (base);
-  temp_filename = xmalloc (len + sizeof("/ccXXXXXX") + 1);
-  strcpy (temp_filename, base);
-  if (len > 0 && temp_filename[len-1] != '/')
-    temp_filename[len++] = '/';
-  strcpy (temp_filename + len, "ccXXXXXX");
-
-  mktemp (temp_filename);
-  temp_filename_length = strlen (temp_filename);
-}
 \f
 /* Routine to add variables to the environment.  */
 
 #ifndef HAVE_PUTENV
 
+int
 putenv (str)
      char *str;
 {
@@ -473,7 +685,6 @@ putenv (str)
   char **envp;
   int num_envs = 0;
   int name_len = 1;
-  int str_len = strlen (str);
   char *p = str;
   int ch;
 
@@ -491,15 +702,17 @@ putenv (str)
       if (!strncmp (str, *envp, name_len))
        {
          *envp = str;
-         return;
+         return 0;
        }
     }
 
   /* Add a new environment variable */
   environ = (char **) xmalloc (sizeof (char *) * (num_envs+2));
   *environ = str;
-  bcopy (old_environ, environ+1, sizeof (char *) * (num_envs+1));
+  bcopy ((char *) old_environ, (char *) (environ + 1),
+        sizeof (char *) * (num_envs+1));
 
+  return 0;
 #endif /* VMS */
 }
 
@@ -510,22 +723,6 @@ putenv (str)
 #define PATH_SEPARATOR ':'
 #endif
 
-/* Structure to hold all the directories in which to search for files to
-   execute.  */
-
-struct prefix_list
-{
-  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 */
-  char *name;                 /* Name of this list (used in config stuff) */
-};
-
 /* We maintain two prefix lists: one from COMPILER_PATH environment variable
    and one from the PATH variable.  */
 
@@ -538,15 +735,10 @@ static struct path_prefix cpath, path;
 static char *target_machine = TARGET_MACHINE;
 #endif
 
-/* Names under which we were executed.  Never return one of those files in our
-   searches.  */
-
-static char *our_file_name, *last_file_name;
-\f
 /* Search for NAME using prefix list PPREFIX.  We only look for executable
    files. 
 
-   Return 0 if not found, otherwise return its name, allocated with malloc. */
+   Return 0 if not found, otherwise return its name, allocated with malloc.  */
 
 static char *
 find_a_file (pprefix, name)
@@ -557,6 +749,9 @@ find_a_file (pprefix, name)
   struct prefix_list *pl;
   int len = pprefix->max_len + strlen (name) + 1;
 
+  if (debug)
+    fprintf (stderr, "Looking for '%s'\n", name);
+  
 #ifdef EXECUTABLE_SUFFIX
   len += strlen (EXECUTABLE_SUFFIX);
 #endif
@@ -565,37 +760,48 @@ find_a_file (pprefix, name)
 
   /* Determine the filename to execute (special case for absolute paths).  */
 
-  if (*name == '/')
+  if (*name == '/'
+#ifdef DIR_SEPARATOR
+      || (DIR_SEPARATOR == '\\' && name[1] == ':'
+      && (name[2] == DIR_SEPARATOR || name[2] == '/'))
+#endif
+      )
     {
       if (access (name, X_OK) == 0)
        {
          strcpy (temp, name);
+
+         if (debug)
+           fprintf (stderr, "  - found: absolute path\n");
+         
          return temp;
        }
+
+      if (debug)
+       fprintf (stderr, "  - failed to locate using absolute path\n");
     }
   else
     for (pl = pprefix->plist; pl; pl = pl->next)
       {
        strcpy (temp, pl->prefix);
        strcat (temp, name);
-       if (strcmp (temp, our_file_name) != 0
-           && ! (last_file_name != 0 && strcmp (temp, last_file_name) == 0)
-           /* This is a kludge, but there seems no way around it.  */
-           && strcmp (temp, "./ld") != 0
-           && access (temp, X_OK) == 0)
+       
+       if (access (temp, X_OK) == 0)
          return temp;
 
 #ifdef EXECUTABLE_SUFFIX
        /* Some systems have a suffix for executable files.
           So try appending that.  */
        strcat (temp, EXECUTABLE_SUFFIX);
-       if (strcmp (temp, our_file_name) != 0
-           && ! (last_file_name != 0 && strcmp (temp, last_file_name) == 0)
-           && access (temp, X_OK) == 0)
+       
+       if (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;
 }
@@ -643,43 +849,56 @@ prefix_from_env (env, pprefix)
      char *env;
      struct path_prefix *pprefix;
 {
-  char *p = getenv (env);
+  char *p;
+  GET_ENVIRONMENT (p, env);
 
   if (p)
-    {
-      char *startp, *endp;
-      char *nstore = (char *) xmalloc (strlen (p) + 3);
+    prefix_from_string (p, pprefix);
+}
+
+static void
+prefix_from_string (p, pprefix)
+     char *p;
+     struct path_prefix *pprefix;
+{
+  char *startp, *endp;
+  char *nstore = (char *) xmalloc (strlen (p) + 3);
 
-      startp = endp = p;
-      while (1)
+  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)
        {
-         if (*endp == PATH_SEPARATOR || *endp == 0)
+         strncpy (nstore, startp, endp-startp);
+         if (endp == startp)
            {
-             strncpy (nstore, startp, endp-startp);
-             if (endp == startp)
-               {
-                 strcpy (nstore, "./");
-               }
-             else if (endp[-1] != '/')
-               {
-                 nstore[endp-startp] = '/';
-                 nstore[endp-startp+1] = 0;
-               }
-             else
-               nstore[endp-startp] = 0;
-
-             add_prefix (pprefix, nstore);
-             if (*endp == 0)
-               break;
-             endp = startp = endp + 1;
+             strcpy (nstore, "./");
+           }
+         else if (endp[-1] != '/')
+           {
+             nstore[endp-startp] = '/';
+             nstore[endp-startp+1] = 0;
            }
          else
-           endp++;
+           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++;
     }
 }
 \f
-/* Main program. */
+/* Main program.  */
 
 int
 main (argc, argv)
@@ -689,70 +908,74 @@ main (argc, argv)
   char *ld_suffix      = "ld";
   char *full_ld_suffix = ld_suffix;
   char *real_ld_suffix = "real-ld";
-  char *full_real_ld_suffix = real_ld_suffix;
-#if 0
-  char *gld_suffix     = "gld";
-  char *full_gld_suffix        = gld_suffix;
-#endif
+  char *collect_ld_suffix = "collect-ld";
   char *nm_suffix      = "nm";
   char *full_nm_suffix = nm_suffix;
   char *gnm_suffix     = "gnm";
   char *full_gnm_suffix        = gnm_suffix;
+#ifdef LDD_SUFFIX
+  char *ldd_suffix     = LDD_SUFFIX;
+  char *full_ldd_suffix        = ldd_suffix;
+#endif
   char *strip_suffix   = "strip";
   char *full_strip_suffix = strip_suffix;
   char *gstrip_suffix  = "gstrip";
   char *full_gstrip_suffix = gstrip_suffix;
   char *arg;
   FILE *outf;
+#ifdef COLLECT_EXPORT_LIST
+  FILE *exportf;
+  FILE *importf;
+#endif
   char *ld_file_name;
-  char *c_file_name;
   char *p;
   char **c_argv;
   char **c_ptr;
-  char **ld1_argv      = (char **) xcalloc (sizeof (char *), argc+2);
+  char **ld1_argv      = (char **) xcalloc (sizeof (char *), argc+3);
   char **ld1           = ld1_argv;
-  char **ld2_argv      = (char **) xcalloc (sizeof (char *), argc+5);
+  char **ld2_argv      = (char **) xcalloc (sizeof (char *), argc+6);
   char **ld2           = ld2_argv;
+  char **object_lst    = (char **) xcalloc (sizeof (char *), argc);
+  char **object                = object_lst;
   int first_file;
   int num_c_args       = argc+7;
-  int len;
-  int clen;
 
 #ifdef DEBUG
   debug = 1;
-  vflag = 1;
 #endif
 
-  our_file_name = argv[0];
+  /* Parse command line early for instances of -debug.  This allows
+     the debug flag to be set before functions like find_a_file()
+     are called.  */
+  {
+    int i;
+    
+    for (i = 1; argv[i] != NULL; i ++)
+      if (! strcmp (argv[i], "-debug"))
+       debug = 1;
+    vflag = debug;
+  }
 
+#ifndef DEFAULT_A_OUT_NAME
   output_file = "a.out";
+#else
+  output_file = DEFAULT_A_OUT_NAME;
+#endif
 
-  /* We must check that we do not call ourselves in an infinite
-     recursion loop. We save the name used for us in the COLLECT_NAME
-     environment variable, first getting the previous value.
-
-     To be fully safe, we need to maintain a list of names that name
-     been used, but, in practice, two names are enough.  */
-
-  last_file_name = getenv ("COLLECT_NAME");
-
-  p = (char *) xcalloc (sizeof (char *),
-                       strlen (our_file_name) + strlen ("COLLECT_NAME=") + 1);
-  sprintf (p, "COLLECT_NAME=%s", our_file_name);
-  putenv (p);
-
-  p = (char *) getenv ("COLLECT_GCC_OPTIONS");
-  if (p)
-    while (*p)
-      {
-       char *q = p;
-       while (*q && *q != ' ') q++;
-       if (*p == '-' && p[1] == 'm')
-         num_c_args++;
+  obstack_begin (&temporary_obstack, 0);
+  obstack_begin (&permanent_obstack, 0);
+  temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0);
 
-       if (*q) q++;
-       p = q;
-      }
+  current_demangling_style = gnu_demangling;
+  p = getenv ("COLLECT_GCC_OPTIONS");
+  while (p && *p)
+    {
+      char *q = extract_string (&p);
+      if (*q == '-' && (q[1] == 'm' || q[1] == 'f'))
+       num_c_args++;
+    }
+  obstack_free (&temporary_obstack, temporary_firstobj);
+  ++num_c_args;
 
   c_ptr = c_argv = (char **) xcalloc (sizeof (char *), num_c_args);
 
@@ -787,7 +1010,7 @@ main (argc, argv)
 #ifdef CROSS_COMPILE
   /* 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 took in the system directories, we need to
+     But it we look for a program in the system directories, we need to
      qualify the program name with the target machine.  */
 
   full_ld_suffix
@@ -796,12 +1019,6 @@ main (argc, argv)
   strcat (full_ld_suffix, "-");
   strcat (full_ld_suffix, ld_suffix);
 
-  full_real_ld_suffix
-    = xcalloc (strlen (real_ld_suffix) + strlen (target_machine) + 2, 1);
-  strcpy (full_real_ld_suffix, target_machine);
-  strcat (full_real_ld_suffix, "-");
-  strcat (full_real_ld_suffix, real_ld_suffix);
-
 #if 0
   full_gld_suffix
     = xcalloc (strlen (gld_suffix) + strlen (target_machine) + 2, 1);
@@ -822,6 +1039,14 @@ main (argc, argv)
   strcat (full_gnm_suffix, "-");
   strcat (full_gnm_suffix, gnm_suffix);
 
+#ifdef LDD_SUFFIX
+  full_ldd_suffix
+    = xcalloc (strlen (ldd_suffix) + strlen (target_machine) + 2, 1);
+  strcpy (full_ldd_suffix, target_machine);
+  strcat (full_ldd_suffix, "-");
+  strcat (full_ldd_suffix, ldd_suffix);
+#endif
+
   full_strip_suffix
     = xcalloc (strlen (strip_suffix) + strlen (target_machine) + 2, 1);
   strcpy (full_strip_suffix, target_machine);
@@ -837,55 +1062,52 @@ main (argc, argv)
 
   /* Try to discover a valid linker/nm/strip to use.  */
 
-#if 0
-  /* Search the (target-specific) compiler dirs for `gld'.  */
-  ld_file_name = find_a_file (&cpath, gld_suffix);
-  /* Search the ordinary system bin directories
-     for `gld' (if native linking) or `TARGET-gld' (if cross).  */
-  if (ld_file_name == 0)
-    ld_file_name = find_a_file (&path, full_gld_suffix);
-#else
-  ld_file_name = 0;
-#endif
-  /* Likewise for `real-ld'.  */
-  if (ld_file_name == 0)
-    ld_file_name = find_a_file (&cpath, real_ld_suffix);
-  if (ld_file_name == 0)
-    ld_file_name = find_a_file (&path, full_real_ld_suffix);
   /* Maybe we know the right file to use (if not cross).  */
 #ifdef REAL_LD_FILE_NAME
+  ld_file_name = find_a_file (&path, REAL_LD_FILE_NAME);
   if (ld_file_name == 0)
-    ld_file_name = find_a_file (&path, REAL_LD_FILE_NAME);
 #endif
-  /* This would be the right place to search the compiler dirs
-     for `ld', but we don't do that, since this program is installed
-     there as `ld'.  */
+  /* Search the (target-specific) compiler dirs for ld'.  */
+  ld_file_name = find_a_file (&cpath, real_ld_suffix);
+  /* Likewise for `collect-ld'.  */
+  if (ld_file_name == 0)
+    ld_file_name = find_a_file (&cpath, collect_ld_suffix);
+  /* 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, ld_suffix);
   /* 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, full_ld_suffix);
 
+#ifdef REAL_NM_FILE_NAME
+  nm_file_name = find_a_file (&path, REAL_NM_FILE_NAME);
+  if (nm_file_name == 0)
+#endif
   nm_file_name = find_a_file (&cpath, gnm_suffix);
   if (nm_file_name == 0)
     nm_file_name = find_a_file (&path, full_gnm_suffix);
   if (nm_file_name == 0)
     nm_file_name = find_a_file (&cpath, nm_suffix);
-#ifdef REAL_NM_FILE_NAME
-  if (nm_file_name == 0)
-    nm_file_name = find_a_file (&path, REAL_NM_FILE_NAME);
-#endif
   if (nm_file_name == 0)
     nm_file_name = find_a_file (&path, full_nm_suffix);
 
+#ifdef LDD_SUFFIX
+  ldd_file_name = find_a_file (&cpath, ldd_suffix);
+  if (ldd_file_name == 0)
+    ldd_file_name = find_a_file (&path, full_ldd_suffix);
+#endif
+
+#ifdef REAL_STRIP_FILE_NAME
+  strip_file_name = find_a_file (&path, REAL_STRIP_FILE_NAME);
+  if (strip_file_name == 0)
+#endif
   strip_file_name = find_a_file (&cpath, gstrip_suffix);
   if (strip_file_name == 0)
     strip_file_name = find_a_file (&path, full_gstrip_suffix);
   if (strip_file_name == 0)
     strip_file_name = find_a_file (&cpath, strip_suffix);
-#ifdef REAL_STRIP_FILE_NAME
-  if (strip_file_name == 0)
-    strip_file_name = find_a_file (&path, REAL_STRIP_FILE_NAME);
-#endif
   if (strip_file_name == 0)
     strip_file_name = find_a_file (&path, full_strip_suffix);
 
@@ -914,17 +1136,54 @@ main (argc, argv)
 
   *ld1++ = *ld2++ = ld_file_name;
 
-  /* Make temp file names. */
-  choose_temp_base ();
+  /* Make temp file names.  */
+  temp_filename = choose_temp_base ();
+  temp_filename_length = strlen (temp_filename);
   c_file = xcalloc (temp_filename_length + sizeof (".c"), 1);
   o_file = xcalloc (temp_filename_length + sizeof (".o"), 1);
+#ifdef COLLECT_EXPORT_LIST
+  export_file = xmalloc (temp_filename_length + sizeof (".x"));
+  import_file = xmalloc (temp_filename_length + sizeof (".p"));
+#endif
+  ldout = xmalloc (temp_filename_length + sizeof (".ld"));
+  sprintf (ldout, "%s.ld", temp_filename);
   sprintf (c_file, "%s.c", temp_filename);
   sprintf (o_file, "%s.o", temp_filename);
+#ifdef COLLECT_EXPORT_LIST
+  sprintf (export_file, "%s.x", temp_filename);
+  sprintf (import_file, "%s.p", temp_filename);
+#endif
   *c_ptr++ = c_file_name;
   *c_ptr++ = "-c";
   *c_ptr++ = "-o";
   *c_ptr++ = o_file;
 
+#ifdef COLLECT_EXPORT_LIST
+  /* Generate a list of directories from LIBPATH.  */
+  prefix_from_env ("LIBPATH", &libpath_lib_dirs);
+  /* Add to this list also two standard directories where
+     AIX loader always searches for libraries.  */
+  add_prefix (&libpath_lib_dirs, "/lib");
+  add_prefix (&libpath_lib_dirs, "/usr/lib");
+#endif
+
+  /* Get any options that the upper GCC wants to pass to the sub-GCC.  
+
+     AIX support needs to know if -shared has been specified before
+     parsing commandline arguments.  */
+
+  p = getenv ("COLLECT_GCC_OPTIONS");
+  while (p && *p)
+    {
+      char *q = extract_string (&p);
+      if (*q == '-' && (q[1] == 'm' || q[1] == 'f'))
+       *c_ptr++ = obstack_copy0 (&permanent_obstack, q, strlen (q));
+      if (strncmp (q, "-shared", sizeof ("-shared") - 1) == 0)
+       shared_obj = 1;
+    }
+  obstack_free (&temporary_obstack, temporary_firstobj);
+  *c_ptr++ = "-fno-exceptions";
+
   /* !!! When GCC calls collect2,
      it does not know whether it is calling collect2 or ld.
      So collect2 cannot meaningfully understand any options
@@ -932,29 +1191,76 @@ main (argc, argv)
      If you propose to make GCC pass some other option,
      just imagine what will happen if ld is really ld!!!  */
 
-  /* Parse arguments.  Remember output file spec, pass the rest to ld. */
+  /* Parse arguments.  Remember output file spec, pass the rest to ld.  */
   /* After the first file, put in the c++ rt0.  */
 
   first_file = 1;
-  while ((arg = *++argv) != (char *)0)
+  while ((arg = *++argv) != (char *) 0)
     {
       *ld1++ = *ld2++ = arg;
 
       if (arg[0] == '-')
+       {
          switch (arg[1])
            {
+#ifdef COLLECT_EXPORT_LIST
+           /* We want to disable automatic exports on AIX when user
+              explicitly puts an export list in command line */
+           case 'b':
+             if (arg[2] == 'E' || strncmp (&arg[2], "export", 6) == 0)
+                export_flag = 1;
+             break;
+#endif
+
            case 'd':
              if (!strcmp (arg, "-debug"))
                {
-                 debug = 1;
-                 vflag = 1;
+                 /* Already parsed.  */
                  ld1--;
                  ld2--;
                }
              break;
 
+           case 'l':
+             if (first_file)
+               {
+                 /* place o_file BEFORE this argument! */
+                 first_file = 0;
+                 ld2--;
+                 *ld2++ = o_file;
+                 *ld2++ = arg;
+               }
+#ifdef COLLECT_EXPORT_LIST
+             {
+               /* Resolving full library name.  */
+               char *s = resolve_lib_name (arg+2);
+
+               /* If we will use an import list for this library,
+                  we should exclude it from ld args.  */
+               if (use_import_list (s))
+                 {
+                   ld1--;
+                   ld2--;
+                 }
+
+               /* Saving a full library name.  */
+               add_to_list (&libs, s);
+             }
+#endif
+             break;
+
+#ifdef COLLECT_EXPORT_LIST
+           /* Saving directories where to search for libraries.  */
+                   case 'L':
+             add_prefix (&cmdline_lib_dirs, arg+2);
+             break;
+#endif
+
            case 'o':
-             output_file = (arg[2] == '\0') ? argv[1] : &arg[2];
+             if (arg[2] == '\0')
+               output_file = *ld1++ = *ld2++ = *++argv;
+             else
+               output_file = &arg[2];
              break;
 
            case 'r':
@@ -963,10 +1269,10 @@ main (argc, argv)
              break;
 
            case 's':
-             if (arg[2] == '\0')
+             if (arg[2] == '\0' && do_collecting)
                {
                  /* We must strip after the nm run, otherwise C++ linking
-                    won't work.  Thus we strip in the second ld run, or
+                    will not work.  Thus we strip in the second ld run, or
                     else with strip if there is no second ld run.  */
                  strip_flag = 1;
                  ld1--;
@@ -978,32 +1284,91 @@ main (argc, argv)
                vflag = 1;
              break;
            }
-
-      else if (first_file
-              && (p = rindex (arg, '.')) != (char *)0
-              && strcmp (p, ".o") == 0)
+       }
+      else if ((p = rindex (arg, '.')) != (char *) 0
+              && (strcmp (p, ".o") == 0 || strcmp (p, ".a") == 0
+                  || strcmp (p, ".so") == 0))
        {
-         first_file = 0;
-         *ld2++ = o_file;
+         if (first_file)
+           {
+             first_file = 0;
+             if (p[1] == 'o')
+               *ld2++ = o_file;
+             else
+               {
+                 /* place o_file BEFORE this argument! */
+                 ld2--;
+                 *ld2++ = o_file;
+                 *ld2++ = arg;
+               }
+           }
+         if (p[1] == 'o')
+           *object++ = arg;
+#ifdef COLLECT_EXPORT_LIST
+         /* libraries can be specified directly, i.e. without -l flag.  */
+                 else
+                   { 
+             /* If we will use an import list for this library,
+                we should exclude it from ld args.  */
+             if (use_import_list (arg))
+               {
+                 ld1--;
+                 ld2--;
+               }
+
+             /* Saving a full library name.  */
+              add_to_list (&libs, arg);
+            }
+#endif
        }
     }
 
-  /* Get any options that the upper GCC wants to pass to the sub-GCC.  */
-  p = (char *) getenv ("COLLECT_GCC_OPTIONS");
-  if (p)
-    while (*p)
-      {
-       char *q = p;
-       while (*q && *q != ' ') q++;
-       if (*p == '-' && (p[1] == 'm' || p[1] == 'f'))
-         *c_ptr++ = savestring (p, q - p);
+#ifdef COLLECT_EXPORT_LIST
+  /* This is added only for debugging purposes.  */
+  if (debug)
+    {
+      fprintf (stderr, "List of libraries:\n");
+      dump_list (stderr, "\t", libs.first);
+    }
 
-       if (*q) q++;
-       p = q;
-      }
+  /* The AIX linker will discard static constructors in object files if
+     nothing else in the file is referenced, so look at them first.  */
+  {
+      char **export_object_lst = object_lst;
+      while (export_object_lst < object)
+       scan_prog_file (*export_object_lst++, PASS_OBJ);
+  }
+  {
+    struct id *list = libs.first;
+    for (; list; list = list->next)
+      scan_prog_file (list->name, PASS_FIRST);
+  }
+  {
+    char *buf1 = alloca (strlen (export_file) + 5);
+    char *buf2 = alloca (strlen (import_file) + 5);
+    sprintf (buf1, "-bE:%s", export_file);
+    sprintf (buf2, "-bI:%s", import_file);
+    *ld1++ = buf1;
+    *ld2++ = buf1;
+    *ld1++ = buf2;
+    *ld2++ = buf2;
+    exportf = fopen (export_file, "w");
+    if (exportf == (FILE *) 0)
+      fatal_perror ("%s", export_file);
+    write_export_file (exportf);
+    if (fclose (exportf))
+      fatal_perror ("closing %s", export_file);
+    importf = fopen (import_file, "w");
+    if (importf == (FILE *) 0)
+      fatal_perror ("%s", import_file);
+    write_import_file (importf);
+    if (fclose (importf))
+      fatal_perror ("closing %s", import_file);
+  }
+#endif
 
   *c_ptr++ = c_file;
-  *c_ptr = *ld1 = *ld2 = (char *)0;
+  *object = *c_ptr = *ld1 = (char *) 0;
 
   if (vflag)
     {
@@ -1023,6 +1388,10 @@ main (argc, argv)
               (c_file_name ? c_file_name : "not found"));
       fprintf (stderr, "nm_file_name        = %s\n",
               (nm_file_name ? nm_file_name : "not found"));
+#ifdef LDD_SUFFIX
+      fprintf (stderr, "ldd_file_name       = %s\n",
+              (ldd_file_name ? ldd_file_name : "not found"));
+#endif
       fprintf (stderr, "strip_file_name     = %s\n",
               (strip_file_name ? strip_file_name : "not found"));
       fprintf (stderr, "c_file              = %s\n",
@@ -1049,18 +1418,44 @@ main (argc, argv)
       fprintf (stderr, "\n");
     }
 
-  /* Load the program, searching all libraries.
-     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. */
+  /* Load the program, searching all libraries and attempting to provide
+     undefined symbols from repository information.  */
 
-  fork_execute ("ld", ld1_argv);
+  /* On AIX we do this later.  */
+#ifndef COLLECT_EXPORT_LIST
+  do_tlink (ld1_argv, object_lst); 
+#endif
 
-  /* If -r, don't build the constructor or destructor list, just return now.  */
-  if (rflag)
-    return 0;
+  /* 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
+      /* But make sure we delete the export file we may have created.  */
+      if (export_file != 0 && export_file[0])
+       maybe_unlink (export_file);
+      if (import_file != 0 && import_file[0])
+       maybe_unlink (import_file);
+#endif
+      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.  */
+
+  /* On AIX we already done scanning for global constructors/destructors.  */
+#ifndef COLLECT_EXPORT_LIST
   scan_prog_file (output_file, PASS_FIRST);
+#endif
+
+#ifdef SCAN_LIBRARIES
+  scan_libraries (output_file);
+#endif
 
   if (debug)
     {
@@ -1068,8 +1463,20 @@ main (argc, argv)
       fprintf (stderr, "%d destructor(s)  found\n", destructors.number);
     }
 
-  if (constructors.number == 0 && destructors.number == 0)
+  if (constructors.number == 0 && destructors.number == 0
+      && frame_tables.number == 0
+#if defined (SCAN_LIBRARIES) || defined (COLLECT_EXPORT_LIST)
+      /* If we will be running these functions ourselves, we want to emit
+        stubs into the shared library so that we do not have to relink
+        dependent programs when we add static objects.  */
+      && ! shared_obj
+#endif
+      )
     {
+#ifdef COLLECT_EXPORT_LIST
+      /* Doing tlink without additional code generation */
+      do_tlink (ld1_argv, object_lst);
+#endif
       /* Strip now if it was requested on the command line.  */
       if (strip_flag)
        {
@@ -1079,11 +1486,17 @@ main (argc, argv)
          strip_argv[2] = (char *) 0;
          fork_execute ("strip", strip_argv);
        }
+
+#ifdef COLLECT_EXPORT_LIST
+      maybe_unlink (export_file);
+      maybe_unlink (import_file);
+#endif
       return 0;
     }
 
+  maybe_unlink(output_file);
   outf = fopen (c_file, "w");
-  if (outf == (FILE *)0)
+  if (outf == (FILE *) 0)
     fatal_perror ("%s", c_file);
 
   write_c_file (outf, c_file);
@@ -1091,34 +1504,76 @@ main (argc, argv)
   if (fclose (outf))
     fatal_perror ("closing %s", c_file);
 
+  /* Tell the linker that we have initializer and finalizer functions.  */
+#ifdef LD_INIT_SWITCH
+  *ld2++ = LD_INIT_SWITCH;
+  *ld2++ = initname;
+  *ld2++ = LD_FINI_SWITCH;
+  *ld2++ = fininame;
+#endif
+  *ld2 = (char*) 0;
+
+#ifdef COLLECT_EXPORT_LIST
+  if (shared_obj)
+    {
+      add_to_list (&exports, initname);
+      add_to_list (&exports, fininame);
+      add_to_list (&exports, "_GLOBAL__DI");
+      add_to_list (&exports, "_GLOBAL__DD");
+      exportf = fopen (export_file, "w");
+      if (exportf == (FILE *) 0)
+       fatal_perror ("%s", export_file);
+      write_export_file (exportf);
+      if (fclose (exportf))
+       fatal_perror ("closing %s", export_file);
+    }
+#endif
+
   if (debug)
     {
       fprintf (stderr, "\n========== output_file = %s, c_file = %s\n",
               output_file, c_file);
       write_c_file (stderr, "stderr");
       fprintf (stderr, "========== end of c_file\n\n");
+#ifdef COLLECT_EXPORT_LIST
+      fprintf (stderr, "\n========== export_file = %s\n", export_file);
+      write_export_file (stderr);
+      fprintf (stderr, "========== end of export_file\n\n");
+#endif
     }
 
   /* Assemble the constructor and destructor tables.
-     Link the tables in with the rest of the program. */
+     Link the tables in with the rest of the program.  */
 
   fork_execute ("gcc",  c_argv);
+#ifdef COLLECT_EXPORT_LIST
+  /* 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 */
   fork_execute ("ld", ld2_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);
+#endif 
 
   maybe_unlink (c_file);
   maybe_unlink (o_file);
+
+#ifdef COLLECT_EXPORT_LIST
+  maybe_unlink (export_file);
+  maybe_unlink (import_file);
+#endif
+
   return 0;
 }
 
 \f
-/* Wait for a process to finish, and exit if a non-zero status is found. */
+/* Wait for a process to finish, and exit if a non-zero status is found.  */
 
-static void
-do_wait (prog)
+int
+collect_wait (prog)
      char *prog;
 {
   int status;
@@ -1126,11 +1581,9 @@ do_wait (prog)
   wait (&status);
   if (status)
     {
-      int sig = status & 0x7F;
-      int ret;
-
-      if (sig != -1 && sig != 0)
+      if (WIFSIGNALED (status))
        {
+         int sig = WTERMSIG (status);
 #ifdef NO_SYS_SIGLIST
          error ("%s terminated with signal %d %s",
                 prog,
@@ -1144,25 +1597,35 @@ do_wait (prog)
                 (status & 0200) ? ", core dumped" : "");
 #endif
 
-         my_exit (127);
+         collect_exit (FATAL_EXIT_CODE);
        }
 
-      ret = ((status & 0xFF00) >> 8);
-      if (ret != -1 && ret != 0)
-       {
-         error ("%s returned %d exit status", prog, ret);
-         my_exit (ret);
-       }
+      if (WIFEXITED (status))
+       return WEXITSTATUS (status);
+    }
+  return 0;
+}
+
+static void
+do_wait (prog)
+     char *prog;
+{
+  int ret = collect_wait (prog);
+  if (ret != 0)
+    {
+      error ("%s returned %d exit status", prog, ret);
+      collect_exit (ret);
     }
 }
 
 \f
 /* Fork and execute a program, and wait for the reply.  */
 
-static void
-fork_execute (prog, argv)
+void
+collect_execute (prog, argv, redir)
      char *prog;
      char **argv;
+     char *redir;
 {
   int pid;
 
@@ -1176,7 +1639,7 @@ fork_execute (prog, argv)
       else
        fprintf (stderr, "[cannot find %s]", prog);
 
-      for (p_argv = &argv[1]; (str = *p_argv) != (char *)0; p_argv++)
+      for (p_argv = &argv[1]; (str = *p_argv) != (char *) 0; p_argv++)
        fprintf (stderr, " %s", str);
 
       fprintf (stderr, "\n");
@@ -1185,25 +1648,52 @@ fork_execute (prog, argv)
   fflush (stdout);
   fflush (stderr);
 
-  /* If we can't find a program we need, complain error.  Do this here
-     since we might not end up needing something that we couldn't find.  */
+  /* 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);
 
+#ifndef __CYGWIN32__
   pid = vfork ();
   if (pid == -1)
-    fatal_perror ("vfork");
+    {
+#ifdef vfork
+      fatal_perror ("fork");
+#else
+      fatal_perror ("vfork");
+#endif
+    }
 
   if (pid == 0)                        /* child context */
     {
+      if (redir)
+       {
+         unlink (redir);
+         if (freopen (redir, "a", stdout) == NULL)
+           fatal_perror ("redirecting stdout: %s", redir);
+         if (freopen (redir, "a", stderr) == NULL)
+           fatal_perror ("redirecting stderr: %s", redir);
+       }
+
       execvp (argv[0], argv);
       fatal_perror ("executing %s", prog);
     }
+#else
+  pid = _spawnvp (_P_NOWAIT, argv[0], argv);
+  if (pid == -1)
+    fatal ("spawnvp failed");
+#endif
+}
 
+static void
+fork_execute (prog, argv)
+     char *prog;
+     char **argv;
+{
+  collect_execute (prog, argv, NULL);
   do_wait (prog);
 }
-
 \f
 /* Unlink a file unless we are debugging.  */
 
@@ -1217,131 +1707,843 @@ maybe_unlink (file)
     fprintf (stderr, "[Leaving %s]\n", file);
 }
 
-\f
-/* Add a name to a linked list.  */
+\f
+/* Add a name to a linked list.  */
+
+static void
+add_to_list (head_ptr, name)
+     struct head *head_ptr;
+     char *name;
+{
+  struct id *newid
+    = (struct id *) xcalloc (sizeof (struct id) + strlen (name), 1);
+  struct id *p;
+  static long sequence_number = 0;
+  strcpy (newid->name, name);
+
+  if (head_ptr->first)
+    head_ptr->last->next = newid;
+  else
+    head_ptr->first = newid;
+
+  /* Check for duplicate symbols.  */
+  for (p = head_ptr->first;
+       strcmp (name, p->name) != 0;
+       p = p->next)
+    ;
+  if (p != newid)
+    {
+      head_ptr->last->next = 0;
+      free (newid);
+      return;
+    }
+
+  newid->sequence = ++sequence_number;
+  head_ptr->last = newid;
+  head_ptr->number++;
+}
+
+/* Write: `prefix', the names on list LIST, `suffix'.  */
+
+static void
+write_list (stream, prefix, list)
+     FILE *stream;
+     char *prefix;
+     struct id *list;
+{
+  while (list)
+    {
+      fprintf (stream, "%sx%d,\n", prefix, list->sequence);
+      list = list->next;
+    }
+}
+
+#ifdef COLLECT_EXPORT_LIST
+/* This function is really used only on AIX, but may be useful.  */
+static int
+is_in_list (prefix, list)
+     char *prefix;
+     struct id *list;
+{
+  while (list)
+    {
+      if (!strcmp (prefix, list->name)) return 1;
+      list = list->next;
+    }
+    return 0;
+}
+#endif
+
+/* Added for debugging purpose.  */
+#ifdef COLLECT_EXPORT_LIST
+static void
+dump_list (stream, prefix, list)
+     FILE *stream;
+     char *prefix;
+     struct id *list;
+{
+  while (list)
+    {
+      fprintf (stream, "%s%s,\n", prefix, list->name);
+      list = list->next;
+    }
+}
+#endif
+
+#if 0
+static void
+dump_prefix_list (stream, prefix, list)
+     FILE *stream;
+     char *prefix;
+     struct prefix_list *list;
+{
+  while (list)
+    {
+      fprintf (stream, "%s%s,\n", prefix, list->prefix);
+      list = list->next;
+    }
+}
+#endif
+
+static void
+write_list_with_asm (stream, prefix, list)
+     FILE *stream;
+     char *prefix;
+     struct id *list;
+{
+  while (list)
+    {
+      fprintf (stream, "%sx%d __asm__ (\"%s\");\n",
+              prefix, list->sequence, list->name);
+      list = list->next;
+    }
+}
+
+/* Write out the constructor and destructor tables statically (for a shared
+   object), along with the functions to execute them.  */
+
+static void
+write_c_file_stat (stream, name)
+     FILE *stream;
+     char *name;
+{
+  char *prefix, *p, *q;
+  int frames = (frame_tables.number > 0);
+
+  /* Figure out name of output_file, stripping off .so version.  */
+  p = rindex (output_file, '/');
+  if (p == 0)
+    p = (char *) output_file;
+  else
+    p++;
+  q = p;
+  while (q)
+    {
+      q = index (q,'.');
+      if (q == 0)
+       {
+         q = p + strlen (p);
+         break;
+       }
+      else
+       {
+         if (strncmp (q, ".so", 3) == 0)
+           {
+             q += 3;
+             break;
+           }
+         else
+           q++;
+       }
+    }
+  /* q points to null at end of the string (or . of the .so version) */
+  prefix = xmalloc (q - p + 1);
+  strncpy (prefix, p, q - p);
+  prefix[q - p] = 0;
+  for (q = prefix; *q; q++)
+    if (!ISALNUM (*q))
+      *q = '_';
+  if (debug)
+    fprintf (stderr, "\nwrite_c_file - output name is %s, prefix is %s\n",
+            output_file, prefix);
+
+#define INIT_NAME_FORMAT "_GLOBAL__FI_%s"
+  initname = xmalloc (strlen (prefix) + sizeof (INIT_NAME_FORMAT) - 2);
+  sprintf (initname, INIT_NAME_FORMAT, prefix);
+
+#define FINI_NAME_FORMAT "_GLOBAL__FD_%s"
+  fininame = xmalloc (strlen (prefix) + sizeof (FINI_NAME_FORMAT) - 2);
+  sprintf (fininame, FINI_NAME_FORMAT, prefix);
+
+  free (prefix);
+
+  /* Write the tables as C code  */
+
+  fprintf (stream, "static int count;\n");
+  fprintf (stream, "typedef void entry_pt();\n");
+  write_list_with_asm (stream, "extern entry_pt ", constructors.first);
+
+  if (frames)
+    {
+      write_list_with_asm (stream, "extern void *", frame_tables.first);
+
+      fprintf (stream, "\tstatic void *frame_table[] = {\n");
+      write_list (stream, "\t\t&", frame_tables.first);
+      fprintf (stream, "\t0\n};\n");
+
+      /* This must match what's in frame.h.  */
+      fprintf (stream, "struct object {\n");
+      fprintf (stream, "  void *pc_begin;\n");
+      fprintf (stream, "  void *pc_end;\n");
+      fprintf (stream, "  void *fde_begin;\n");
+      fprintf (stream, "  void *fde_array;\n");
+      fprintf (stream, "  __SIZE_TYPE__ count;\n");
+      fprintf (stream, "  struct object *next;\n");
+      fprintf (stream, "};\n");
+
+      fprintf (stream, "extern void __register_frame_info_table (void *, struct object *);\n");
+      fprintf (stream, "extern void *__deregister_frame_info (void *);\n");
+
+      fprintf (stream, "static void reg_frame () {\n");
+      fprintf (stream, "\tstatic struct object ob;\n");
+      fprintf (stream, "\t__register_frame_info_table (frame_table, &ob);\n");
+      fprintf (stream, "\t}\n");
+
+      fprintf (stream, "static void dereg_frame () {\n");
+      fprintf (stream, "\t__deregister_frame_info (frame_table);\n");
+      fprintf (stream, "\t}\n");
+    }
+
+  fprintf (stream, "void %s() {\n", initname);
+  if (constructors.number > 0 || frames)
+    {
+      fprintf (stream, "\tstatic entry_pt *ctors[] = {\n");
+      write_list (stream, "\t\t", constructors.first);
+      if (frames)
+       fprintf (stream, "\treg_frame,\n");
+      fprintf (stream, "\t};\n");
+      fprintf (stream, "\tentry_pt **p;\n");
+      fprintf (stream, "\tif (count++ != 0) return;\n");
+      fprintf (stream, "\tp = ctors + %d;\n", constructors.number + frames);
+      fprintf (stream, "\twhile (p > ctors) (*--p)();\n");
+    }
+  else
+    fprintf (stream, "\t++count;\n");
+  fprintf (stream, "}\n");
+  write_list_with_asm (stream, "extern entry_pt ", destructors.first);
+  fprintf (stream, "void %s() {\n", fininame);
+  if (destructors.number > 0 || frames)
+    {
+      fprintf (stream, "\tstatic entry_pt *dtors[] = {\n");
+      write_list (stream, "\t\t", destructors.first);
+      if (frames)
+       fprintf (stream, "\tdereg_frame,\n");
+      fprintf (stream, "\t};\n");
+      fprintf (stream, "\tentry_pt **p;\n");
+      fprintf (stream, "\tif (--count != 0) return;\n");
+      fprintf (stream, "\tp = dtors;\n");
+      fprintf (stream, "\twhile (p < dtors + %d) (*p++)();\n",
+              destructors.number + frames);
+    }
+  fprintf (stream, "}\n");
+
+  if (shared_obj)
+    {
+      fprintf (stream, "void _GLOBAL__DI() {\n\t%s();\n}\n", initname);
+      fprintf (stream, "void _GLOBAL__DD() {\n\t%s();\n}\n", fininame);
+    }
+}
+
+/* Write the constructor/destructor tables.  */
+
+#ifndef LD_INIT_SWITCH
+static void
+write_c_file_glob (stream, name)
+     FILE *stream;
+     char *name;
+{
+  /* Write the tables as C code  */
+
+  int frames = (frame_tables.number > 0);
+
+  fprintf (stream, "typedef void entry_pt();\n\n");
+    
+  write_list_with_asm (stream, "extern entry_pt ", constructors.first);
+
+  if (frames)
+    {
+      write_list_with_asm (stream, "extern void *", frame_tables.first);
+
+      fprintf (stream, "\tstatic void *frame_table[] = {\n");
+      write_list (stream, "\t\t&", frame_tables.first);
+      fprintf (stream, "\t0\n};\n");
+
+      /* This must match what's in frame.h.  */
+      fprintf (stream, "struct object {\n");
+      fprintf (stream, "  void *pc_begin;\n");
+      fprintf (stream, "  void *pc_end;\n");
+      fprintf (stream, "  void *fde_begin;\n");
+      fprintf (stream, "  void *fde_array;\n");
+      fprintf (stream, "  __SIZE_TYPE__ count;\n");
+      fprintf (stream, "  struct object *next;\n");
+      fprintf (stream, "};\n");
+
+      fprintf (stream, "extern void __register_frame_info_table (void *, struct object *);\n");
+      fprintf (stream, "extern void *__deregister_frame_info (void *);\n");
+
+      fprintf (stream, "static void reg_frame () {\n");
+      fprintf (stream, "\tstatic struct object ob;\n");
+      fprintf (stream, "\t__register_frame_info_table (frame_table, &ob);\n");
+      fprintf (stream, "\t}\n");
+
+      fprintf (stream, "static void dereg_frame () {\n");
+      fprintf (stream, "\t__deregister_frame_info (frame_table);\n");
+      fprintf (stream, "\t}\n");
+    }
+
+  fprintf (stream, "\nentry_pt * __CTOR_LIST__[] = {\n");
+  fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number + frames);
+  write_list (stream, "\t", constructors.first);
+  if (frames)
+    fprintf (stream, "\treg_frame,\n");
+  fprintf (stream, "\t0\n};\n\n");
+
+  write_list_with_asm (stream, "extern entry_pt ", destructors.first);
+
+  fprintf (stream, "\nentry_pt * __DTOR_LIST__[] = {\n");
+  fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number + frames);
+  write_list (stream, "\t", destructors.first);
+  if (frames)
+    fprintf (stream, "\tdereg_frame,\n");
+  fprintf (stream, "\t0\n};\n\n");
+
+  fprintf (stream, "extern entry_pt %s;\n", NAME__MAIN);
+  fprintf (stream, "entry_pt *__main_reference = %s;\n\n", NAME__MAIN);
+}
+#endif /* ! LD_INIT_SWITCH */
+
+static void
+write_c_file (stream, name)
+     FILE *stream;
+     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
+static void
+write_export_file (stream)
+     FILE *stream;
+{
+  struct id *list = exports.first;
+  for (; list; list = list->next)
+    fprintf (stream, "%s\n", list->name);
+}
+
+static void
+write_import_file (stream)
+     FILE *stream;
+{
+  struct id *list = imports.first;
+  fprintf (stream, "%s\n", "#! .");
+  for (; list; list = list->next)
+    fprintf (stream, "%s\n", list->name);
+}
+#endif
+\f
+#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__.  */
+
+static void
+scan_prog_file (prog_name, which_pass)
+     char *prog_name;
+     enum pass which_pass;
+{
+  void (*int_handler) ();
+  void (*quit_handler) ();
+  char *nm_argv[4];
+  int pid;
+  int argc = 0;
+  int pipe_fd[2];
+  char *p, buf[1024];
+  FILE *inf;
+
+  if (which_pass == PASS_SECOND)
+    return;
+
+  /* If we do not have an `nm', complain.  */
+  if (nm_file_name == 0)
+    fatal ("cannot find `nm'");
+
+  nm_argv[argc++] = nm_file_name;
+  if (NM_FLAGS[0] != '\0')
+    nm_argv[argc++] = NM_FLAGS;
+
+  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)
+    {
+      char **p_argv;
+      char *str;
+
+      for (p_argv = &nm_argv[0]; (str = *p_argv) != (char *) 0; p_argv++)
+       fprintf (stderr, " %s", str);
+
+      fprintf (stderr, "\n");
+    }
+
+  fflush (stdout);
+  fflush (stderr);
+
+  /* Spawn child nm on pipe */
+  pid = vfork ();
+  if (pid == -1)
+    {
+#ifdef vfork
+      fatal_perror ("fork");
+#else
+      fatal_perror ("vfork");
+#endif
+    }
+
+  if (pid == 0)                        /* child context */
+    {
+      /* 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, nm_argv);
+      fatal_perror ("executing %s", nm_file_name);
+    }
+
+  /* Parent context from here on.  */
+  int_handler  = (void (*) ())signal (SIGINT,  SIG_IGN);
+#ifdef SIGQUIT
+  quit_handler = (void (*) ())signal (SIGQUIT, SIG_IGN);
+#endif
+
+  if (close (pipe_fd[1]) < 0)
+    fatal_perror ("close (%d)", pipe_fd[1]);
+
+  if (debug)
+    fprintf (stderr, "\nnm output with constructors/destructors.\n");
+
+  /* Read each line of nm output.  */
+  while (fgets (buf, sizeof buf, inf) != (char *) 0)
+    {
+      int ch, ch2;
+      char *name, *end;
+
+      /* If it contains a constructor or destructor name, add the name
+        to the appropriate list.  */
+
+      for (p = buf; (ch = *p) != '\0' && ch != '\n' && ch != '_'; p++)
+       if (ch == ' ' && p[1] == 'U' && p[2] == ' ')
+         break;
+
+      if (ch != '_')
+       continue;
+  
+      name = p;
+      /* Find the end of the symbol name.
+        Do not include `|', because Encore nm can tack that on the end.  */
+      for (end = p; (ch2 = *end) != '\0' && !ISSPACE (ch2) && ch2 != '|';
+          end++)
+       continue;
+
+
+      *end = '\0';
+      switch (is_ctor_dtor (name))
+       {
+       case 1:
+         if (which_pass != PASS_LIB)
+           add_to_list (&constructors, name);
+         break;
+
+       case 2:
+         if (which_pass != PASS_LIB)
+           add_to_list (&destructors, name);
+         break;
+
+       case 3:
+         if (which_pass != PASS_LIB)
+           fatal ("init function found in object %s", prog_name);
+#ifndef LD_INIT_SWITCH
+         add_to_list (&constructors, name);
+#endif
+         break;
+
+       case 4:
+         if (which_pass != PASS_LIB)
+           fatal ("fini function found in object %s", prog_name);
+#ifndef LD_FINI_SWITCH
+         add_to_list (&destructors, name);
+#endif
+         break;
+
+       case 5:
+         if (which_pass != PASS_LIB)
+           add_to_list (&frame_tables, name);
+
+       default:                /* not a constructor or destructor */
+         continue;
+       }
+
+      if (debug)
+       fprintf (stderr, "\t%s\n", buf);
+    }
+
+  if (debug)
+    fprintf (stderr, "\n");
+
+  if (fclose (inf) != 0)
+    fatal_perror ("fclose of pipe");
+
+  do_wait (nm_file_name);
+
+  signal (SIGINT,  int_handler);
+#ifdef SIGQUIT
+  signal (SIGQUIT, quit_handler);
+#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
-add_to_list (head_ptr, name)
-     struct head *head_ptr;
+mapfile (name)
      char *name;
 {
-  struct id *newid = (struct id *) xcalloc (sizeof (*newid) + strlen (name), 1);
-  static long sequence_number = 0;
-  newid->sequence = ++sequence_number;
-  strcpy (newid->name, 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 == -1)
+    fatal ("unable to mmap file '%s'", name);
+
+  close (fp);
+}
 
-  if (head_ptr->first)
-    head_ptr->last->next = newid;
-  else
-    head_ptr->first = newid;
+/* Helpers for locatelib.  */
 
-  head_ptr->last = newid;
-  head_ptr->number++;
+static char *libname;
+
+static int
+libselect (d)
+     struct direct *d;
+{
+  return (strncmp (libname, d->d_name, strlen (libname)) == 0);
 }
 
-/* Write: `prefix', the names on list LIST, `suffix'.  */
+/* 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.
 
-static void
-write_list (stream, prefix, list)
-     FILE *stream;
-     char *prefix;
-     struct id *list;
+   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 (d1, d2)
+     struct direct **d1, **d2;
 {
-  while (list)
+  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]))
     {
-      fprintf (stream, "%sx%d,\n", prefix, list->sequence);
-      list = list->next;
+      ++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 a 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 a 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
-write_list_with_asm (stream, prefix, list)
-     FILE *stream;
-     char *prefix;
-     struct id *list;
+locatelib (name)
+     char *name;
 {
-  while (list)
+  static char **l;
+  static int cnt;
+  char buf[MAXPATHLEN];
+  char *p, *q;
+  char **pp;
+
+  if (l == 0)
     {
-      fprintf (stream, "%sx%d __asm__ (\"%s\");\n",
-              prefix, list->sequence, list->name);
-      list = list->next;
+      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 = (char *) malloc (strlen (ld_rules) + 1);
+         strcpy (ldr, ld_rules);
+       }
+      p = getenv ("LD_LIBRARY_PATH");
+      q = 0;
+      if (p)
+       {
+         cnt++;
+         for (q = p ; *q != 0; q++)
+           if (*q == ':')
+             cnt++;
+         q = (char *) malloc (strlen (p) + 1);
+         strcpy (q, p);
+       }
+      l = (char **) malloc ((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)
+       fprintf (stderr, "not found\n");
+      else
+       fatal ("dynamic dependency %s not found", name);
     }
 }
 
-/* Write the constructor/destructor tables. */
+/* 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
-write_c_file (stream, name)
-     FILE *stream;
-     char *name;
+static void 
+scan_libraries (prog_name)
+     char *prog_name;
 {
-  /* Write the tables as C code  */
+  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;
 
-  fprintf (stream, "typedef void entry_pt();\n\n");
-    
-  write_list_with_asm (stream, "extern entry_pt ", constructors.first);
-    
-  fprintf (stream, "\nentry_pt * __CTOR_LIST__[] = {\n");
-  fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number);
-  write_list (stream, "\t", constructors.first);
-  fprintf (stream, "\t0\n};\n\n");
+  code = (char *) (N_TXTOFF (*header) + (long) header);
+  data = (char *) (N_DATOFF (*header) + (long) header);
+  symtab = (struct nlist *) (N_SYMOFF (*header) + (long) header);
 
-  write_list_with_asm (stream, "extern entry_pt ", destructors.first);
+  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;
+    }
 
-  fprintf (stream, "\nentry_pt * __DTOR_LIST__[] = {\n");
-  fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number);
-  write_list (stream, "\t", destructors.first);
-  fprintf (stream, "\t0\n};\n\n");
+  if (debug)
+    fprintf (stderr, "dynamic dependencies.\n");
 
-  fprintf (stream, "extern entry_pt __main;\n");
-  fprintf (stream, "entry_pt *__main_reference = __main;\n\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);
+       }
+    }
 
-\f
-#ifdef OBJECT_FORMAT_NONE
+  if (debug)
+    fprintf (stderr, "\n");
 
-/* Generic version to scan the name list of the loaded program for
-   the symbols g++ uses for static constructors and destructors.
+  /* 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);
+}
 
-   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__.  */
+#else  /* SUNOS4_SHARED_LIBRARIES */
+#ifdef LDD_SUFFIX
 
-static void
-scan_prog_file (prog_name, which_pass)
+/* Use the List Dynamic Dependencies program to find shared libraries that
+   the output file depends upon and their initialization/finalization
+   routines, if any.  */
+
+static void 
+scan_libraries (prog_name)
      char *prog_name;
-     enum pass which_pass;
 {
+  static struct head libraries;                /* list of shared libraries found */
+  struct id *list;
   void (*int_handler) ();
   void (*quit_handler) ();
-  char *nm_argv[4];
+  char *ldd_argv[4];
   int pid;
   int argc = 0;
   int pipe_fd[2];
-  char *p, buf[1024];
+  char buf[1024];
   FILE *inf;
 
-  if (which_pass != PASS_FIRST)
-    return;
-
-  /* If we don't have an `nm', complain.  */
-  if (nm_file_name == 0)
-    fatal ("cannot find `nm'");
-
-  nm_argv[argc++] = "nm";
-  if (NM_FLAGS[0] != '\0')
-    nm_argv[argc++] = NM_FLAGS;
+  /* If we do not have an `ldd', complain.  */
+  if (ldd_file_name == 0)
+    {
+      error ("cannot find `ldd'");
+      return;
+    }
 
-  nm_argv[argc++] = prog_name;
-  nm_argv[argc++] = (char *)0;
+  ldd_argv[argc++] = ldd_file_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)
+  if (inf == (FILE *) 0)
     fatal_perror ("fdopen");
 
   /* Trace if needed.  */
@@ -1350,8 +2552,7 @@ scan_prog_file (prog_name, which_pass)
       char **p_argv;
       char *str;
 
-      fprintf (stderr, "%s", nm_file_name);
-      for (p_argv = &nm_argv[1]; (str = *p_argv) != (char *)0; p_argv++)
+      for (p_argv = &ldd_argv[0]; (str = *p_argv) != (char *) 0; p_argv++)
        fprintf (stderr, " %s", str);
 
       fprintf (stderr, "\n");
@@ -1360,10 +2561,16 @@ scan_prog_file (prog_name, which_pass)
   fflush (stdout);
   fflush (stderr);
 
-  /* Spawn child nm on pipe */
+  /* Spawn child ldd on pipe */
   pid = vfork ();
   if (pid == -1)
-    fatal_perror ("vfork");
+    {
+#ifdef vfork
+      fatal_perror ("fork");
+#else
+      fatal_perror ("vfork");
+#endif
+    }
 
   if (pid == 0)                        /* child context */
     {
@@ -1377,77 +2584,74 @@ scan_prog_file (prog_name, which_pass)
       if (close (pipe_fd[1]) < 0)
        fatal_perror ("close (%d)", pipe_fd[1]);
 
-      execv (nm_file_name, nm_argv);
-      fatal_perror ("executing %s", nm_file_name);
+      execv (ldd_file_name, ldd_argv);
+      fatal_perror ("executing %s", ldd_file_name);
     }
 
   /* Parent context from here on.  */
-  int_handler  = (void (*) ())signal (SIGINT,  SIG_IGN);
+  int_handler  = (void (*) ()) signal (SIGINT,  SIG_IGN);
 #ifdef SIGQUIT
-  quit_handler = (void (*) ())signal (SIGQUIT, SIG_IGN);
+  quit_handler = (void (*) ()) signal (SIGQUIT, SIG_IGN);
 #endif
 
   if (close (pipe_fd[1]) < 0)
     fatal_perror ("close (%d)", pipe_fd[1]);
 
   if (debug)
-    fprintf (stderr, "\nnm output with constructors/destructors.\n");
+    fprintf (stderr, "\nldd output with constructors/destructors.\n");
 
-  /* Read each line of nm output.  */
-  while (fgets (buf, sizeof buf, inf) != (char *)0)
+  /* Read each line of ldd output.  */
+  while (fgets (buf, sizeof buf, inf) != (char *) 0)
     {
       int ch, ch2;
-      char *name, *end;
-
-      /* If it contains a constructor or destructor name, add the name
-        to the appropriate list. */
+      char *name, *end, *p = buf;
 
-      for (p = buf; (ch = *p) != '\0' && ch != '\n' && ch != '_'; p++)
-       ;
-
-      if (ch == '\0' || ch == '\n')
+      /* Extract names of libraries and add to list.  */
+      PARSE_LDD_OUTPUT (p);
+      if (p == 0)
        continue;
-  
+
       name = p;
-      /* Find the end of the symbol name.
-        Don't include `|', because Encore nm can tack that on the end.  */
-      for (end = p; (ch2 = *end) != '\0' && !isspace (ch2) && ch2 != '|';
+      if (strncmp (name, "not found", sizeof ("not found") - 1) == 0)
+       fatal ("dynamic dependency %s not found", buf);
+
+      /* Find the end of the symbol name.  */
+      for (end = p; 
+          (ch2 = *end) != '\0' && ch2 != '\n' && !ISSPACE (ch2) && ch2 != '|';
           end++)
        continue;
-
       *end = '\0';
-      switch (is_ctor_dtor (name))
-       {
-       case 1:
-         add_to_list (&constructors, name);
-         break;
-
-       case 2:
-         add_to_list (&destructors, name);
-         break;
 
-       default:                /* not a constructor or destructor */
-         continue;
-       }
+      if (access (name, R_OK) == 0)
+        add_to_list (&libraries, name);
+      else
+       fatal ("unable to open dynamic dependency '%s'", buf);
 
       if (debug)
        fprintf (stderr, "\t%s\n", buf);
     }
-
   if (debug)
     fprintf (stderr, "\n");
 
   if (fclose (inf) != 0)
     fatal_perror ("fclose of pipe");
 
-  do_wait (nm_file_name);
+  do_wait (ldd_file_name);
 
   signal (SIGINT,  int_handler);
 #ifdef SIGQUIT
   signal (SIGQUIT, quit_handler);
 #endif
+
+  /* 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 */
 
 \f
@@ -1469,8 +2673,11 @@ scan_prog_file (prog_name, which_pass)
 #   define GCC_SYMENT          SYMENT
 #   define GCC_OK_SYMBOL(X) \
      (((X).n_sclass == C_EXT) && \
-        (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) || \
-         ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT)))
+      ((X).n_scnum > N_UNDEF) && \
+      (((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))
 #   define GCC_SYMINC(X)       ((X).n_numaux+1)
 #   define GCC_SYMZERO(X)      0
 #   define GCC_CHECK_HDR(X)    (1)
@@ -1494,73 +2701,267 @@ scan_prog_file (prog_name, which_pass)
 {
   LDFILE *ldptr = NULL;
   int sym_index, sym_count;
+  int is_shared = 0;
+#ifdef COLLECT_EXPORT_LIST
+  /* Should we generate an import list for given prog_name?  */
+  int import_flag = (which_pass == PASS_OBJ ? 0 : use_import_list (prog_name));
+#endif
 
-  if (which_pass != PASS_FIRST)
+  if (which_pass != PASS_FIRST && which_pass != PASS_OBJ)
     return;
 
-  if ((ldptr = ldopen (prog_name, ldptr)) == NULL)
-    fatal ("%s: can't open as COFF file", prog_name);
-      
-  if (!MY_ISCOFF (HEADER (ldptr).f_magic))
-    fatal ("%s: not a COFF file", prog_name);
+#ifdef COLLECT_EXPORT_LIST
+  /* We do not need scanning for some standard C libraries.  */
+  if (which_pass == PASS_FIRST && ignore_library (prog_name))
+    return;
 
-  if (GCC_CHECK_HDR (ldptr))
+  /* On AIX we have a loop, because there is not much difference
+     between an object and an archive. This trick allows us to
+     eliminate scan_libraries() function.  */
+  do
     {
-      sym_count = GCC_SYMBOLS (ldptr);
-      sym_index = GCC_SYMZERO (ldptr);
-      while (sym_index < sym_count)
+#endif
+      if ((ldptr = ldopen (prog_name, ldptr)) != NULL)
        {
-         GCC_SYMENT symbol;
 
-         if (ldtbread (ldptr, sym_index, &symbol) <= 0)
-           break;
-         sym_index += GCC_SYMINC (symbol);
+         if (!MY_ISCOFF (HEADER (ldptr).f_magic))
+           fatal ("%s: not a COFF file", prog_name);
 
-         if (GCC_OK_SYMBOL (symbol))
+#ifdef COLLECT_EXPORT_LIST
+         /* Is current archive member a shared object?  */
+         is_shared = HEADER (ldptr).f_flags & F_SHROBJ;
+#endif
+         if (GCC_CHECK_HDR (ldptr))
            {
-             char *name;
+             sym_count = GCC_SYMBOLS (ldptr);
+             sym_index = GCC_SYMZERO (ldptr);
+             while (sym_index < sym_count)
+               {
+                 GCC_SYMENT symbol;
 
-             if ((name = ldgetname (ldptr, &symbol)) == NULL)
-               continue;               /* should never happen */
+                 if (ldtbread (ldptr, sym_index, &symbol) <= 0)
+                   break;
+                 sym_index += GCC_SYMINC (symbol);
 
-#ifdef _AIX
-             /* All AIX function names begin with a dot. */
-             if (*name++ != '.')
-               continue;
-#endif
+                 if (GCC_OK_SYMBOL (symbol))
+                   {
+                     char *name;
 
-             switch (is_ctor_dtor (name))
-               {
-               case 1:
-                 add_to_list (&constructors, name);
-                 break;
+                     if ((name = ldgetname (ldptr, &symbol)) == NULL)
+                       continue;               /* should never happen */
 
-               case 2:
-                 add_to_list (&destructors, name);
-                 break;
+#ifdef XCOFF_DEBUGGING_INFO
+                     /* All AIX function names have a duplicate entry
+                        beginning with a dot.  */
+                     if (*name == '.')
+                       ++name;
+#endif
 
-               default:                /* not a constructor or destructor */
-                 continue;
-               }
+                     switch (is_ctor_dtor (name))
+                       {
+                       case 1:
+                         if (! is_shared) add_to_list (&constructors, name);
+#ifdef COLLECT_EXPORT_LIST
+                         if (which_pass == PASS_OBJ)
+                           add_to_list (&exports, name);
+                         /* If this symbol was undefined and we are building
+                            an import list, we should add a symbol to this
+                            list.  */
+                         else
+                           if (import_flag
+                               && is_in_list (name, undefined.first))
+                             add_to_list (&imports, name);
+#endif
+                         break;
+
+                       case 2:
+                         if (! is_shared) add_to_list (&destructors, name);
+#ifdef COLLECT_EXPORT_LIST
+                         if (which_pass == PASS_OBJ)
+                           add_to_list (&exports, name);
+                         /* If this symbol was undefined and we are building
+                            an import list, we should add a symbol to this
+                            list.  */
+                         else
+                           if (import_flag
+                               && is_in_list (name, undefined.first))
+                             add_to_list (&imports, name);
+#endif
+                         break;
+
+#ifdef COLLECT_EXPORT_LIST
+                       case 3:
+                         if (is_shared)
+                           add_to_list (&constructors, name);
+                         break;
+
+                       case 4:
+                         if (is_shared)
+                           add_to_list (&destructors, name);
+                         break;
+#endif
+
+                       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 or add
+                            them to import list.  */
+                         if (shared_obj) 
+                           {
+                             if (which_pass == PASS_OBJ && (! export_flag))
+                               add_to_list (&exports, name);
+                             else if (! is_shared && which_pass == PASS_FIRST
+                                      && import_flag
+                                      && is_in_list(name, undefined.first))
+                               add_to_list (&imports, name);
+                           }
+#endif
+                         continue;
+                       }
 
 #if !defined(EXTENDED_COFF)
-             if (debug)
-               fprintf (stderr, "\tsec=%d class=%d type=%s%o %s\n",
-                        symbol.n_scnum, symbol.n_sclass,
-                        (symbol.n_type ? "0" : ""), symbol.n_type,
-                        name);
+                     if (debug)
+                       fprintf (stderr, "\tsec=%d class=%d type=%s%o %s\n",
+                                symbol.n_scnum, symbol.n_sclass,
+                                (symbol.n_type ? "0" : ""), symbol.n_type,
+                                name);
 #else
-             if (debug)
-               fprintf (stderr, "\tiss = %5d, value = %5d, index = %5d, name = %s\n",
-                        symbol.iss, symbol.value, symbol.index, name);
+                     if (debug)
+                       fprintf (stderr,
+                                "\tiss = %5d, value = %5d, index = %5d, name = %s\n",
+                                symbol.iss, symbol.value, symbol.index, name);
+#endif
+                   }
+#ifdef COLLECT_EXPORT_LIST
+                 /* If we are building a shared object we should collect
+                    information about undefined symbols for later
+                    import list generation.  */
+                 else if (shared_obj && GCC_UNDEF_SYMBOL (symbol))
+                   {
+                     char *name;
+
+                     if ((name = ldgetname (ldptr, &symbol)) == NULL)
+                       continue;               /* should never happen */
+
+                     /* All AIX function names have a duplicate entry
+                        beginning with a dot.  */
+                     if (*name == '.')
+                       ++name;
+                     add_to_list (&undefined, name);
+                   }
 #endif
+               }
            }
        }
+      else
+       {
+         fatal ("%s: cannot open as COFF file", prog_name);
+       }
+#ifdef COLLECT_EXPORT_LIST
+      /* On AIX loop continues while there are more members in archive.  */
     }
-
+  while (ldclose (ldptr) == FAILURE);
+#else
+  /* Otherwise we simply close ldptr.  */
   (void) ldclose(ldptr);
+#endif
+}
+
+
+#ifdef COLLECT_EXPORT_LIST
+
+/* This new function is used to decide whether we should
+   generate import list for an object or to use it directly.  */
+static int
+use_import_list (prog_name)
+     char *prog_name;
+{
+  char *p;
+
+  /* If we do not build a shared object then import list should not be used.  */
+  if (! shared_obj) return 0;
+
+  /* Currently we check only for libgcc, but this can be changed in future.  */
+  p = strstr (prog_name, "libgcc.a");
+  if (p != 0 && (strlen (p) == sizeof ("libgcc.a") - 1))
+    return 1;
+  return 0;
+}
+
+/* Given a library name without "lib" prefix, this function
+   returns a full library name including a path.  */
+static char *
+resolve_lib_name (name)
+     char *name;
+{
+  char *lib_buf;
+  int i, j, l = 0;
+
+  for (i = 0; libpaths[i]; i++)
+    if (libpaths[i]->max_len > l)
+      l = libpaths[i]->max_len;
+
+  lib_buf = xmalloc (l + strlen(name) + 10);
+
+  for (i = 0; libpaths[i]; i++)
+    {
+      struct prefix_list *list = libpaths[i]->plist;
+      for (; list; list = list->next)
+       {
+         for (j = 0; libexts[j]; j++)
+           {
+              /* The following lines are needed because path_prefix list
+                 may contain directories both with trailing '/' and
+                 without it.  */
+              char *p = "";
+              if (list->prefix[strlen(list->prefix)-1] != '/')
+                p = "/";
+                     sprintf (lib_buf, "%s%slib%s.%s",
+                      list->prefix, p, name, libexts[j]);
+if (debug) fprintf (stderr, "searching for: %s\n", lib_buf);
+             if (file_exists (lib_buf))
+               {
+if (debug) fprintf (stderr, "found: %s\n", lib_buf);
+                 return (lib_buf);
+               }
+           }
+       }
+    }
+  if (debug)
+    fprintf (stderr, "not found\n");
+  else
+    fatal ("Library lib%s not found", name);
+  return (NULL);
+}
+
+/* Array of standard AIX libraries which should not
+   be scanned for ctors/dtors.  */
+static char* aix_std_libs[] = {
+  "/unix",
+  "/lib/libc.a",
+  "/lib/libc_r.a",
+  "/usr/lib/libc.a",
+  "/usr/lib/libc_r.a",
+  "/usr/lib/threads/libc.a",
+  "/usr/ccs/lib/libc.a",
+  "/usr/ccs/lib/libc_r.a",
+  NULL
+};
+
+/* This function checks the filename and returns 1
+   if this name matches the location of a standard AIX library. */
+static int
+ignore_library (name)
+     char *name;
+{
+  char **p = &aix_std_libs[0];
+  while (*p++ != NULL)
+    if (! strcmp (name, *p)) return 1;
+  return 0;
 }
 
+#endif
+
 #endif /* OBJECT_FORMAT_COFF */
 
 \f
@@ -1609,21 +3010,15 @@ struct file_info
 };
 
 extern int decode_mach_o_hdr ();
-
 extern int encode_mach_o_hdr ();
 
-static void bad_header ();
-
-static void print_header ();
-
-static void print_load_command ();
-
-static void add_func_table ();
-
-static struct file_info        *read_file ();
-
-static void end_file ();
-
+static void add_func_table     PROTO((mo_header_t *, load_all_t *,
+                                      symbol_info_t *, int));
+static void print_header       PROTO((mo_header_t *));
+static void print_load_command PROTO((load_union_t *, size_t, int));
+static void bad_header         PROTO((int));
+static struct file_info        *read_file  PROTO((char *, int, int));
+static void end_file           PROTO((struct file_info *));
 \f
 /* OSF/rose specific version to scan the name list of the loaded
    program for the symbols g++ uses for static constructors and
@@ -1659,7 +3054,7 @@ scan_prog_file (prog_name, which_pass)
 
   prog_fd = open (prog_name, (rw) ? O_RDWR : O_RDONLY);
   if (prog_fd < 0)
-    fatal_perror ("can't read %s", prog_name);
+    fatal_perror ("cannot read %s", prog_name);
 
   obj_file = read_file (prog_name, prog_fd, rw);
   obj = obj_file->start;
@@ -1705,7 +3100,7 @@ scan_prog_file (prog_name, which_pass)
       if (rw)
        {
          load_union_t *ptr = (load_union_t *) xmalloc (load_hdr->hdr.ldci_cmd_size);
-         bcopy ((generic *)load_hdr, (generic *)ptr, load_hdr->hdr.ldci_cmd_size);
+         bcopy ((char *)load_hdr, (char *)ptr, load_hdr->hdr.ldci_cmd_size);
          load_hdr = ptr;
 
          /* null out old command map, because we will rewrite at the end.  */
@@ -1763,10 +3158,10 @@ scan_prog_file (prog_name, which_pass)
            continue;
 
          str_sect = load_array[load_hdr->sym.symc_strings_section].section;
-         if (str_sect == (char *)0)
+         if (str_sect == (char *) 0)
            fatal ("string section missing");
 
-         if (load_cmd->section == (char *)0)
+         if (load_cmd->section == (char *) 0)
            fatal ("section pointer missing");
 
          num_syms = load_hdr->sym.symc_nentries;
@@ -1780,11 +3175,13 @@ scan_prog_file (prog_name, which_pass)
 
              if (rw)
                {
-                 char *n = name;
-                 while (*n == '_')
-                   ++n;
-                 if (*n != 'm' || (n - name) < 2 || strcmp (n, "main"))
+                 char *n = name + strlen (name) - strlen (NAME__MAIN);
+
+                 if ((n - name) < 0 || strcmp (n, NAME__MAIN))
                    continue;
+                 while (n != name)
+                   if (*--n != '_')
+                     continue;
 
                  main_sym = sym;
                }
@@ -1829,11 +3226,11 @@ scan_prog_file (prog_name, which_pass)
        fatal ("no cmd_strings found");
 
       /* Add __main to initializer list.
-        If we are building a program instead of a shared library, don't
+        If we are building a program instead of a shared library, do not
         do anything, since in the current version, you cannot do mallocs
         and such in the constructors.  */
 
-      if (main_sym != (symbol_info_t *)0
+      if (main_sym != (symbol_info_t *) 0
          && ((hdr.moh_flags & MOH_EXECABLE_F) == 0))
        add_func_table (&hdr, load_array, main_sym, FNTC_INITIALIZATION);
 
@@ -1888,7 +3285,7 @@ scan_prog_file (prog_name, which_pass)
          if (debug)
            print_load_command (load_hdr, offset, i);
 
-         bcopy ((generic *)load_hdr, (generic *)(obj + offset), size);
+         bcopy ((char *) load_hdr, (char *) (obj + offset), size);
          offset += size;
        }
     }
@@ -1927,7 +3324,7 @@ add_func_table (hdr_p, load_array, sym, type)
 
   load_cmd = &load_array[load_index];
   load_cmd->load = ptr;
-  load_cmd->section = (char *)0;
+  load_cmd->section = (char *) 0;
 
   /* Fill in func table load command.  */
   ptr->func.ldc_header.ldci_cmd_type = LDC_FUNC_TABLE;
@@ -2036,7 +3433,7 @@ print_load_command (load_hdr, offset, number)
      int number;
 {
   mo_long_t type = load_hdr->hdr.ldci_cmd_type;
-  char *type_str = (char *)0;
+  char *type_str = (char *) 0;
 
   switch (type)
     {
@@ -2061,7 +3458,7 @@ print_load_command (load_hdr, offset, number)
           (long) load_hdr->hdr.ldci_section_off,
           (long) load_hdr->hdr.ldci_section_len);
 
-  if (type_str == (char *)0)
+  if (type_str == (char *) 0)
     fprintf (stderr, ", ty: unknown (%ld)\n", (long) type);
 
   else if (type != LDC_REGION)
@@ -2100,7 +3497,7 @@ static void
 bad_header (status)
      int status;
 {
-  char *msg = (char *)0;
+  char *msg = (char *) 0;
 
   switch (status)
     {
@@ -2112,7 +3509,7 @@ bad_header (status)
     case MO_ERROR_UNSUPPORTED_VERS:    msg = "unsupported version";            break;
     }
 
-  if (msg == (char *)0)
+  if (msg == (char *) 0)
     fatal ("unknown {de,en}code_mach_o_hdr return value %d", status);
   else
     fatal ("%s", msg);
@@ -2150,14 +3547,14 @@ read_file (name, fd, rw)
     page_size = sysconf (_SC_PAGE_SIZE);
 
   p->rounded_size = ((p->size + page_size - 1) / page_size) * page_size;
-  p->start = mmap ((caddr_t)0,
+  p->start = mmap ((caddr_t) 0,
                   (rw) ? p->rounded_size : p->size,
                   (rw) ? (PROT_READ | PROT_WRITE) : PROT_READ,
                   MAP_FILE | MAP_VARIABLE | MAP_SHARED,
                   fd,
                   0L);
 
-  if (p->start != (char *)0 && p->start != (char *)-1)
+  if (p->start != (char *) 0 && p->start != (char *) -1)
     p->use_mmap = 1;
 
   else
@@ -2183,7 +3580,6 @@ read_file (name, fd, rw)
 
   return p;
 }
-
 \f
 /* Do anything necessary to write a file back from memory.  */
 
@@ -2224,16 +3620,16 @@ end_file (ptr)
 
          len = write (ptr->fd, ptr->start, ptr->size);
          if (len < 0)
-           fatal_perror ("read %s", ptr->name);
+           fatal_perror ("write %s", ptr->name);
 
          if (len != ptr->size)
            fatal ("wrote %ld bytes, expected %ld, to %s", len, ptr->size, ptr->name);
        }
 
-      free ((generic *)ptr->start);
+      free (ptr->start);
     }
 
-  free ((generic *)ptr);
+  free (ptr);
 }
 
 #endif /* OBJECT_FORMAT_ROSE */