OSDN Git Service

91th Cygnus<->FSF merge
[pf3gnuchains/gcc-fork.git] / gcc / collect2.c
index 87ae569..e5f404f 100644 (file)
@@ -1,8 +1,6 @@
-/* Collect static initialization info into data structures
-   that can be traversed by C++ initialization and finalization
-   routines.
-
-   Copyright (C) 1992, 1993, 1994, 1995 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, 94, 95, 96, 1997 Free Software Foundation, Inc.
    Contributed by Chris Smith (csmith@convex.com).
    Heavily modified by Michael Meissner (meissner@cygnus.com),
    Per Bothner (bothner@cygnus.com), and John Gilmore (gnu@cygnus.com).
@@ -25,7 +23,7 @@ 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 "config.h"
 #include <sys/types.h>
@@ -35,14 +33,12 @@ Boston, MA 02111-1307, USA.  */
 #include <signal.h>
 #include <sys/file.h>
 #include <sys/stat.h>
-#ifdef NO_WAIT_H
-#include <sys/wait.h>
-#endif
 
 #define COLLECT
 
 #include "demangle.h"
 #include "obstack.h"
+#include "gansidecl.h"
 
 #ifndef errno
 extern int errno;
@@ -63,23 +59,10 @@ char *strerror();
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
-#if !defined (__STDC__) && !defined (const)
-#define const
-#endif
-
 #ifdef USG
 #define vfork fork
 #endif
 
-/* Add prototype support.  */
-#ifndef PROTO
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define PROTO(ARGS) ARGS
-#else
-#define PROTO(ARGS) ()
-#endif
-#endif
-
 #ifndef R_OK
 #define R_OK 4
 #define W_OK 2
@@ -99,13 +82,7 @@ char *strerror();
 #define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
 #endif
 
-/* On MSDOS, write temp files in current dir
-   because there's no place else we can expect to use.  */
-#ifdef __MSDOS__
-#ifndef P_tmpdir
-#define P_tmpdir "./"
-#endif
-#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
@@ -158,6 +135,10 @@ char *strerror();
 #define MY_ISCOFF(X) ISCOFF (X)
 #endif
 
+#ifdef XCOFF_DEBUGGING_INFO
+#define XCOFF_SCAN_LIBS
+#endif
+
 #endif /* OBJECT_FORMAT_COFF */
 
 #ifdef OBJECT_FORMAT_ROSE
@@ -196,7 +177,7 @@ char *strerror();
 #define SYMBOL__MAIN __main
 #endif
 
-#if defined (LDD_SUFFIX) || SUNOS4_SHARED_LIBRARIES
+#if defined (LDD_SUFFIX) || SUNOS4_SHARED_LIBRARIES || defined(XCOFF_SCAN_LIBS)
 #define SCAN_LIBRARIES
 #endif
 
@@ -206,7 +187,7 @@ int do_collecting = 1;
 int do_collecting = 0;
 #endif
 \f
-/* Linked lists of constructor and destructor names. */
+/* Linked lists of constructor and destructor names.  */
 
 struct id 
 {
@@ -248,10 +229,9 @@ 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 *export_file;              /* <xxx>.x for AIX export list. */
-static int  auto_export = 1;           /* true if exporting everything. */
+static char *c_file;                   /* <xxx>.c for constructor/destructor list.  */
+static char *o_file;                   /* <xxx>.o for constructor/destructor list.  */
+static char *export_file;              /* <xxx>.x for AIX export list.  */
 char *ldout;                           /* File for ld errors.  */
 static char *output_file;              /* Output file for ld.  */
 static char *nm_file_name;             /* pathname of nm */
@@ -280,8 +260,8 @@ extern FILE *fdopen ();
 
 struct prefix_list
 {
-  char *prefix;               /* String to prepend to the path. */
-  struct prefix_list *next;   /* Next in linked list. */
+  char *prefix;               /* String to prepend to the path.  */
+  struct prefix_list *next;   /* Next in linked list.  */
 };
 
 struct path_prefix
@@ -296,7 +276,6 @@ void collect_execute                PROTO((char *, char **, char *));
 void dump_file                 PROTO((char *));
 static void handler            PROTO((int));
 static int is_ctor_dtor                PROTO((char *));
-static void choose_temp_base   PROTO((void));
 static int is_in_prefix_list   PROTO((struct path_prefix *, char *, int));
 static char *find_a_file       PROTO((struct path_prefix *, char *));
 static void add_prefix         PROTO((struct path_prefix *, char *));
@@ -392,7 +371,7 @@ collect_exit (status)
 }
 
 \f
-/* Die when sys call fails. */
+/* Die when sys call fails.  */
 
 void
 fatal_perror (string, arg1, arg2, arg3)
@@ -403,10 +382,10 @@ fatal_perror (string, arg1, arg2, arg3)
   fprintf (stderr, "collect2: ");
   fprintf (stderr, string, arg1, arg2, arg3);
   fprintf (stderr, ": %s\n", my_strerror (e));
-  collect_exit (1);
+  collect_exit (FATAL_EXIT_CODE);
 }
 
-/* Just die. */
+/* Just die.  */
 
 void
 fatal (string, arg1, arg2, arg3)
@@ -415,7 +394,7 @@ fatal (string, arg1, arg2, arg3)
   fprintf (stderr, "collect2: ");
   fprintf (stderr, string, arg1, arg2, arg3);
   fprintf (stderr, "\n");
-  collect_exit (1);
+  collect_exit (FATAL_EXIT_CODE);
 }
 
 /* Write error message.  */
@@ -452,6 +431,9 @@ handler (signo)
   if (ldout != 0 && ldout[0])
     maybe_unlink (ldout);
 
+  if (export_file != 0 && export_file[0])
+    maybe_unlink (export_file);
+
   signal (signo, SIG_DFL);
   kill (getpid (), signo);
 }
@@ -466,7 +448,7 @@ xcalloc (size1, size2)
     return ptr;
 
   fatal ("out of memory");
-  return (char *)0;
+  return (char *) 0;
 }
 
 char *
@@ -478,7 +460,7 @@ xmalloc (size)
     return ptr;
 
   fatal ("out of memory");
-  return (char *)0;
+  return (char *) 0;
 }
 
 char *
@@ -567,6 +549,7 @@ dump_file (name)
        break;
       putc (c, stderr);
     }
+  fclose (stream);
 }
 \f
 /* Decide whether the given symbol is:
@@ -625,42 +608,6 @@ 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.  */
 
@@ -772,7 +719,7 @@ is_in_prefix_list (pprefix, string, filep)
 /* 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)
@@ -909,7 +856,7 @@ prefix_from_string (p, pprefix)
     }
 }
 \f
-/* Main program. */
+/* Main program.  */
 
 int
 main (argc, argv)
@@ -955,7 +902,11 @@ main (argc, argv)
   vflag = 1;
 #endif
 
+#ifndef DEFAULT_A_OUT_NAME
   output_file = "a.out";
+#else
+  output_file = DEFAULT_A_OUT_NAME;
+#endif
 
   obstack_begin (&temporary_obstack, 0);
   obstack_begin (&permanent_obstack, 0);
@@ -1195,8 +1146,9 @@ 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);
   export_file = xmalloc (temp_filename_length + sizeof (".x"));
@@ -1217,11 +1169,11 @@ 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;
 
@@ -1239,15 +1191,6 @@ main (argc, argv)
                }
              break;
 
-#ifdef COLLECT_EXPORT_LIST
-           case 'b':
-             if ((!strncmp (arg, "-bE:", 4)
-                  || !strncmp (arg, "-bexport:", 9))
-                 && strcmp (arg, "-bexport:/usr/lib/libg.exp"))
-               auto_export = 0;
-             break;
-#endif
-
            case 'l':
              if (first_file)
                {
@@ -1288,7 +1231,7 @@ main (argc, argv)
              break;
            }
        }
-      else if ((p = rindex (arg, '.')) != (char *)0
+      else if ((p = rindex (arg, '.')) != (char *) 0
               && (strcmp (p, ".o") == 0 || strcmp (p, ".a") == 0))
        {
          if (first_file)
@@ -1337,7 +1280,7 @@ main (argc, argv)
     *ld1++ = buf;
     *ld2++ = buf;
     exportf = fopen (export_file, "w");
-    if (exportf == (FILE *)0)
+    if (exportf == (FILE *) 0)
       fatal_perror ("%s", export_file);
     write_export_file (exportf);
     if (fclose (exportf))
@@ -1346,7 +1289,7 @@ main (argc, argv)
 #endif
 
   *c_ptr++ = c_file;
-  *object = *c_ptr = *ld1 = (char *)0;
+  *object = *c_ptr = *ld1 = (char *) 0;
 
   if (vflag)
     {
@@ -1408,13 +1351,13 @@ main (argc, argv)
   unlink (ldout);
 
   /* If -r or they'll be run via some other method, don't build the
-     constructor or destructor list, just return now. */
+     constructor or destructor list, just return now.  */
   if (rflag || ! do_collecting)
     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. */
+     Write the constructor and destructor tables to a .s file and reload.  */
 
   scan_prog_file (output_file, PASS_FIRST);
 
@@ -1455,7 +1398,7 @@ main (argc, argv)
 
   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);
@@ -1470,7 +1413,7 @@ main (argc, argv)
   *ld2++ = LD_FINI_SWITCH;
   *ld2++ = fininame;
 #endif
-  *ld2 = (char*)0;
+  *ld2 = (char*) 0;
 
 #ifdef COLLECT_EXPORT_LIST
   if (shared_obj)
@@ -1480,7 +1423,7 @@ main (argc, argv)
       add_to_list (&exports, "_GLOBAL__DI");
       add_to_list (&exports, "_GLOBAL__DD");
       exportf = fopen (export_file, "w");
-      if (exportf == (FILE *)0)
+      if (exportf == (FILE *) 0)
        fatal_perror ("%s", export_file);
       write_export_file (exportf);
       if (fclose (exportf))
@@ -1502,7 +1445,7 @@ main (argc, argv)
     }
 
   /* 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);
   fork_execute ("ld", ld2_argv);
@@ -1518,7 +1461,7 @@ main (argc, argv)
 }
 
 \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.  */
 
 int
 collect_wait (prog)
@@ -1545,7 +1488,7 @@ collect_wait (prog)
                 (status & 0200) ? ", core dumped" : "");
 #endif
 
-         collect_exit (127);
+         collect_exit (FATAL_EXIT_CODE);
        }
 
       if (WIFEXITED (status))
@@ -1587,7 +1530,7 @@ collect_execute (prog, argv, redir)
       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");
@@ -1812,7 +1755,7 @@ write_c_file_stat (stream, name)
     }
 }
 
-/* Write the constructor/destructor tables. */
+/* Write the constructor/destructor tables.  */
 
 static void
 write_c_file_glob (stream, name)
@@ -1846,12 +1789,14 @@ 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");
 }
 
 static void
@@ -1900,13 +1845,13 @@ scan_prog_file (prog_name, which_pass)
     nm_argv[argc++] = NM_FLAGS;
 
   nm_argv[argc++] = prog_name;
-  nm_argv[argc++] = (char *)0;
+  nm_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.  */
@@ -1915,7 +1860,7 @@ scan_prog_file (prog_name, which_pass)
       char **p_argv;
       char *str;
 
-      for (p_argv = &nm_argv[0]; (str = *p_argv) != (char *)0; p_argv++)
+      for (p_argv = &nm_argv[0]; (str = *p_argv) != (char *) 0; p_argv++)
        fprintf (stderr, " %s", str);
 
       fprintf (stderr, "\n");
@@ -1964,13 +1909,13 @@ scan_prog_file (prog_name, which_pass)
     fprintf (stderr, "\nnm output with constructors/destructors.\n");
 
   /* Read each line of nm output.  */
-  while (fgets (buf, sizeof buf, inf) != (char *)0)
+  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. */
+        to the appropriate list.  */
 
       for (p = buf; (ch = *p) != '\0' && ch != '\n' && ch != '_'; p++)
        if (ch == ' ' && p[1] == 'U' && p[2] == ' ')
@@ -2049,7 +1994,7 @@ scan_prog_file (prog_name, which_pass)
 #include <link.h>
 #include <sys/mman.h>
 #include <sys/param.h>
-#include <sys/unistd.h>
+#include <unistd.h>
 #include <sys/dir.h>
 
 /* pointers to the object file */
@@ -2095,6 +2040,14 @@ libselect (d)
   return (strncmp (libname, d->d_name, strlen (libname)) == 0);
 }
 
+/* If one file has an additional numeric extension past LIBNAME, then put
+   that one first in the sort.  If both files have additional numeric
+   extensions, then put the one with the higher number first in the sort.
+
+   We must verify that the extension is numeric, because Sun saves the
+   original versions of patched libraries with a .FCS extension.  Files with
+   invalid extensions must go last in the sort, so that they won't be used.  */
+
 static int
 libcompare (d1, d2)
      struct direct **d1, **d2;
@@ -2103,7 +2056,8 @@ libcompare (d1, d2)
   char *e1 = (*d1)->d_name + i2;
   char *e2 = (*d2)->d_name + i2;
 
-  while (*e1 && *e2)
+  while (*e1 && *e2 && *e1 == '.' && *e2 == '.'
+        && e1[1] && isdigit (e1[1]) && e2[1] && isdigit (e2[1]))
     {
       ++e1;
       ++e2;
@@ -2114,9 +2068,23 @@ libcompare (d1, d2)
     }
 
   if (*e1)
-    return 1;
+    {
+      /* 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)
-    return -1;
+    {
+      /* 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;
 }
@@ -2181,7 +2149,7 @@ locatelib (name)
            if (*q == ':')
              {
                *q++ = 0;
-               *pp++ = p;
+               *pp++ = q;
              }
        }
       /* built in directories are /lib, /usr/lib, and /usr/local/lib */
@@ -2384,7 +2352,7 @@ scan_libraries (prog_name)
       int ch, ch2;
       char *name, *end, *p = buf;
 
-      /* Extract names of libraries and add to list. */
+      /* Extract names of libraries and add to list.  */
       PARSE_LDD_OUTPUT (p);
       if (p == 0)
        continue;
@@ -2393,7 +2361,7 @@ scan_libraries (prog_name)
       if (strncmp (name, "not found", sizeof ("not found") - 1) == 0)
        fatal ("dynamic dependency %s not found", buf);
 
-      /* Find the end of the symbol name. */
+      /* Find the end of the symbol name.  */
       for (end = p; 
           (ch2 = *end) != '\0' && ch2 != '\n' && !isspace (ch2) && ch2 != '|';
           end++)
@@ -2507,7 +2475,7 @@ scan_prog_file (prog_name, which_pass)
 
 #ifdef XCOFF_DEBUGGING_INFO
              /* All AIX function names have a duplicate entry beginning
-                with a dot. */
+                with a dot.  */
              if (*name == '.')
                ++name;
 #endif
@@ -2527,8 +2495,6 @@ scan_prog_file (prog_name, which_pass)
                  break;
 
                default:                /* not a constructor or destructor */
-                 if (which_pass == PASS_OBJ && auto_export)
-                   add_to_list (&exports, name);
                  continue;
                }
 
@@ -2550,6 +2516,175 @@ scan_prog_file (prog_name, which_pass)
   (void) ldclose(ldptr);
 }
 
+#ifdef XCOFF_SCAN_LIBS
+/* Scan imported AIX libraries for GCC static ctors and dtors.
+   FIXME: it is possible to link an executable without the actual import
+         library by using an "import file" - a text file listing symbols
+         exported by a library.  To support this, we would have to scan
+         import files as well as actual shared binaries to find GCC ctors.
+   TODO: use memory mapping instead of 'ld' routines, files are already
+        memory mapped, but we could eliminate the extra in-memory copies.
+        Is it worth the effort?  */
+
+static void
+scan_libraries (prog_name)
+     char *prog_name;
+{
+  LDFILE *ldptr;
+  SCNHDR ldsh;
+  static struct path_prefix libpath; /* we should only do this once */
+
+  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);
+
+  /* find and read loader section */
+  if (ldnshread (ldptr, _LOADER, &ldsh))
+    {
+      LDHDR ldh;
+      char *impbuf;
+      int entry;
+
+      FSEEK (ldptr, ldsh.s_scnptr, BEGINNING);
+      FREAD (&ldh, sizeof (ldh), 1, ldptr);
+      /* read import library list */
+      impbuf = alloca (ldh.l_istlen);
+      FSEEK (ldptr, ldh.l_impoff + ldsh.s_scnptr, BEGINNING);
+      FREAD (impbuf, ldh.l_istlen, 1, ldptr);
+
+      if (debug)
+       fprintf (stderr, "LIBPATH=%s\n", impbuf);
+      prefix_from_string (impbuf, &libpath);
+
+      /* skip LIBPATH and empty base and member fields */
+      impbuf += strlen (impbuf) + 3;
+      for (entry = 1; entry < ldh.l_nimpid; ++entry)
+       {
+         char *impath = impbuf;
+         char *implib = impath + strlen (impath) + 1;
+         char *impmem = implib + strlen (implib) + 1;
+         char *soname = NULL;
+         char *trial;
+         int pathlen;
+         LDFILE *libptr = NULL;
+         struct prefix_list *pl;
+         ARCHDR ah;
+
+         impbuf = impmem + strlen (impmem) + 1;
+         if (debug)
+           fprintf (stderr, "PATH+BASE=%s%s\n", impath, implib);
+         /* Skip AIX kernel exports */
+         if (*impath == '/' && *(impath+1) == '\0'
+             && strcmp (implib, "unix") == 0)
+           continue;
+         pathlen = strlen (impath);
+          trial = alloca (MAX (pathlen + 1, libpath.max_len)
+                         + strlen (implib) + 1);
+         if (*impath)
+           {
+             strcpy (trial, impath);
+             if (impath[pathlen - 1] != '/')
+               trial[pathlen++] = '/';
+             strcpy (trial + pathlen, implib);
+             if (access (trial, R_OK) == 0)
+               soname = trial;
+           }
+         else
+           for (pl = libpath.plist; pl; pl = pl->next)
+             {
+               strcpy (trial, pl->prefix);
+               strcat (trial, implib);
+               if (access (trial, R_OK) == 0)
+                 {
+                   soname = trial;
+                   break;
+                 }
+             }
+
+         if (! soname)
+           fatal ("%s: library not found", implib);
+         if (debug)
+           if (*impmem)
+             fprintf (stderr, "%s (%s)\n", soname, impmem);
+           else
+             fprintf (stderr, "%s\n", soname);
+
+         do
+           {
+             /* scan imported shared objects for GCC GLOBAL ctors */
+             short type;
+             if ((libptr = ldopen (soname, libptr)) == NULL)
+               fatal ("%s: can't open import library", soname);
+             if (TYPE (libptr) == ARTYPE)
+               {
+                 LDFILE *memptr;
+                 if (! *impmem)
+                   fatal ("%s: no archive member specified", soname);
+                 ldahread (libptr, &ah);
+                 if (strcmp (ah.ar_name, impmem))
+                   continue;
+               }
+             type = HEADER (libptr).f_magic;
+             if (HEADER (libptr).f_flags & F_SHROBJ)
+               {
+                 SCNHDR soldsh;
+                 LDHDR soldh;
+                 long symcnt, i;
+                 char *ldstrings;
+                 LDSYM *lsyms;
+                 if (!ldnshread (libptr, _LOADER, &soldsh))
+                   fatal ("%s: not an import library", soname);
+                 FSEEK (libptr, soldsh.s_scnptr, BEGINNING);
+                 if (FREAD (&soldh, sizeof (soldh), 1, libptr) != 1)
+                   fatal ("%s: can't read loader section", soname);
+                 /*fprintf (stderr, "\tscanning %s\n", soname);*/
+                 symcnt = soldh.l_nsyms;
+                 lsyms = (LDSYM *) alloca (symcnt * sizeof (*lsyms));
+                 symcnt = FREAD (lsyms, sizeof (*lsyms), symcnt, libptr);
+                 ldstrings = alloca (soldh.l_stlen);
+                 FSEEK (libptr, soldsh.s_scnptr+soldh.l_stoff, BEGINNING);
+                 FREAD (ldstrings, soldh.l_stlen, 1, libptr);
+                 for (i = 0; i < symcnt; ++i)
+                   {
+                     LDSYM *l = lsyms + i;
+                     if (LDR_EXPORT (*l))
+                       {
+                         char *expname = 0;
+                         if (l->l_zeroes)
+                           expname = l->l_name;
+                         else if (l->l_offset < soldh.l_stlen)
+                           expname = ldstrings + l->l_offset;
+                         switch (is_ctor_dtor (expname))
+                           {
+                           case 3:
+                             if (debug)
+                               fprintf (stderr, "\t%s\n", expname);
+                             add_to_list (&constructors, expname);
+                             break;
+
+                           case 4:
+                             add_to_list (&destructors, expname);
+                             break;
+
+                           default: /* not a constructor or destructor */
+                             continue;
+                           }
+                       }
+                   }
+               }
+             else
+               fprintf (stderr, "%s: type = %04X flags = %04X\n", 
+                        ah.ar_name, type, HEADER (libptr).f_flags);
+           }
+         while (ldclose (libptr) == FAILURE);
+         /* printf (stderr, "closed %s\n", soname); */
+       }
+    }
+}
+#endif /* XCOFF_SCAN_LIBS */
+
 #endif /* OBJECT_FORMAT_COFF */
 
 \f
@@ -2603,7 +2738,7 @@ extern int encode_mach_o_hdr ();
 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 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 *));
@@ -2746,10 +2881,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;
@@ -2818,7 +2953,7 @@ scan_prog_file (prog_name, which_pass)
         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);
 
@@ -2873,7 +3008,7 @@ scan_prog_file (prog_name, which_pass)
          if (debug)
            print_load_command (load_hdr, offset, i);
 
-         bcopy ((char *)load_hdr, (char *)(obj + offset), size);
+         bcopy ((char *) load_hdr, (char *) (obj + offset), size);
          offset += size;
        }
     }
@@ -2912,7 +3047,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;
@@ -3021,7 +3156,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)
     {
@@ -3046,7 +3181,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)
@@ -3085,7 +3220,7 @@ static void
 bad_header (status)
      int status;
 {
-  char *msg = (char *)0;
+  char *msg = (char *) 0;
 
   switch (status)
     {
@@ -3097,7 +3232,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);
@@ -3135,14 +3270,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
@@ -3208,7 +3343,7 @@ 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);