*** empty log message ***
authorRichard Stallman <rms@gnu.org>
Thu, 19 Mar 1992 22:07:22 +0000 (22:07 +0000)
committerRichard Stallman <rms@gnu.org>
Thu, 19 Mar 1992 22:07:22 +0000 (22:07 +0000)
From-SVN: r529

gcc/collect2.c

index 814db0b41393484cf3b3e1e77140ce5b1d22d1a1..320ac7d47df909cadd8979c908b959d787ad7fcc 100644 (file)
@@ -29,15 +29,17 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <sys/types.h>
 #include <stdio.h>
 #include <string.h>
-#include <stdlib.h>
 #include <ctype.h>
-#include "gstddef.h"
 #include <errno.h>
 #include <signal.h>
 #include <sys/file.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 
+#ifndef errno
+extern int errno;
+#endif
+
 #define COLLECT
 
 #include "config.h"
@@ -45,15 +47,72 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #ifndef __STDC__
 #include "gvarargs.h"
 #define generic char
-#define PROTO(x) ()
 #define const
 
 #else
-#include "stdarg.h"
+#include "gstdarg.h"
 #define generic void
-#define PROTO(x) x
 #endif
 
+#ifdef USG
+#define vfork fork
+#endif
+
+#ifndef R_OK
+#define R_OK 4
+#define W_OK 2
+#define X_OK 1
+#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 "./"
+#endif
+#endif
+\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.  */
+
+#ifdef CROSS_COMPILE
+#undef OBJECT_FORMAT_COFF
+#undef OBJECT_FORMAT_ROSE
+#endif
+
+/* If we can't 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.  */
+
+#if !defined (OBJECT_FORMAT_COFF) && !defined (OBJECT_FORMAT_ROSE)
+#define OBJECT_FORMAT_NONE
+#endif
+
+#ifdef OBJECT_FORMAT_COFF
+
+#include <a.out.h>
+#include <ar.h>
+
+#ifdef UMAX
+#include <sgs.h>
+#endif
+
+#ifdef _AIX
+#define ISCOFF(magic) \
+  ((magic) == U802WRMAGIC || (magic) == U802ROMAGIC || (magic) == U802TOCMAGIC)
+#endif
+
+#if defined (_AIX) || defined (USG)
+#undef FREAD
+#undef FWRITE
+#endif
+
+#include <ldfcn.h>
+
+#endif /* OBJECT_FORMAT_COFF */
+
 #ifdef OBJECT_FORMAT_ROSE
 
 #ifdef _OSF_SOURCE
@@ -69,25 +128,17 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <mach_o_header.h>
 #include <mach_o_vals.h>
 #include <mach_o_types.h>
+
 #endif /* OBJECT_FORMAT_ROSE */
 
+#ifdef OBJECT_FORMAT_NONE
+
 /* Default flags to pass to nm.  */
 #ifndef NM_FLAGS
 #define NM_FLAGS "-p"
 #endif
 
-#ifdef USG
-#define vfork fork
-#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 "./"
-#endif
-#endif
-
+#endif /* OBJECT_FORMAT_NONE */
 \f
 /* Linked lists of constructor and destructor names. */
 
@@ -112,7 +163,9 @@ enum pass {
   PASS_SECOND                          /* with constructors linked in */
 };
 
+#ifndef NO_SYS_SIGLIST
 extern char *sys_siglist[];
+#endif
 extern char *version_string;
 
 static int vflag;                      /* true if -v */
@@ -129,27 +182,27 @@ static char *nm_file_name;                /* pathname of nm */
 static struct head constructors;       /* list of constructors found */
 static struct head destructors;                /* list of destructors found */
 
-extern char *getenv            PROTO(( const char * ));
-extern char *mktemp            PROTO(( char * ));
-extern int   vfork             PROTO(( void ));
-static void  add_to_list       PROTO(( struct head *headp, char *name ));
-static void  scan_prog_file    PROTO(( char *, enum pass ));
-static void  fork_execute      PROTO(( char *, char **argv ));
-static void  do_wait           PROTO(( char * ));
-static void  write_c_file      PROTO(( FILE *, char * ));
-static void  my_exit           PROTO(( int ));
-static void  handler           PROTO(( int ));
-static void  maybe_unlink      PROTO(( char * ));
-static void  choose_temp_base  PROTO(( void ));
-
-generic                *xcalloc        PROTO(( size_t, size_t ));
-generic                *xmalloc        PROTO(( size_t ));
-
+extern char *getenv ();
+extern char *mktemp ();
+extern int   vfork ();
+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 ();
 \f
 
 #if !defined(HAVE_STRERROR) && !defined(_OSF_SOURCE)
 
-char *strerror (e)
+char *
+strerror (e)
      int e;
 {
   extern char *sys_errlist[];
@@ -175,10 +228,10 @@ static void
 my_exit (status)
      int status;
 {
-  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);
 
   exit (status);
@@ -309,17 +362,15 @@ handler (signo)
     maybe_unlink (o_file);
 
   signal (signo, SIG_DFL);
-
-  fatal ("Caught signal %d [%s]", signo, sys_siglist[signo]);
   kill (getpid (), signo);
 }
 
 \f
 generic *
 xcalloc (size1, size2)
-     size_t size1, size2;
+     int size1, size2;
 {
-  generic *ptr = calloc (size1, size2);
+  generic *ptr = (generic *) calloc (size1, size2);
   if (ptr)
     return ptr;
 
@@ -329,9 +380,9 @@ xcalloc (size1, size2)
 
 generic *
 xmalloc (size)
-     size_t size;
+     int size;
 {
-  generic *ptr = malloc (size);
+  generic *ptr = (generic *) malloc (size);
   if (ptr)
     return ptr;
 
@@ -339,12 +390,68 @@ xmalloc (size)
   return (generic *)0;
 }
 
+/* Make a copy of a string INPUT with size SIZE.  */
+
+char *
+savestring (input, size)
+     char *input;
+     int size;
+{
+  char *output = (char *) xmalloc (size + 1);
+  strcpy (output, input);
+  return output;
+}
+\f
+/* Decide whether the given symbol is:
+   a constructor (1), a destructor (2), or neither (0).  */
+
+static int
+is_ctor_dtor (s)
+     char *s;
+{
+  struct names { char *name; int len; int ret; int two_underscores; };
+
+  register struct names *p;
+  register int ch;
+  register char *orig_s = s;
+
+  static struct names special[] = {
+#ifdef NO_DOLLAR_IN_LABEL
+    { "GLOBAL_.I.", sizeof ("GLOBAL_.I.")-1, 1, 0 },
+    { "GLOBAL_.D.", sizeof ("GLOBAL_.D.")-1, 2, 0 },
+#else
+    { "GLOBAL_$I$", sizeof ("GLOBAL_$I$")-1, 1, 0 },
+    { "GLOBAL_$D$", sizeof ("GLOBAL_$I$")-1, 2, 0 },
+#endif
+    { "sti__", sizeof ("sti__")-1, 1, 1 },
+    { "std__", sizeof ("std__")-1, 2, 1 },
+    { NULL, 0, 0, 0 }
+  };
+
+  while ((ch = *s) == '_')
+    ++s;
+
+  if (s == orig_s)
+    return 0;
+
+  for (p = &special[0]; p->len > 0; p++)
+    {
+      if (ch == p->name[0]
+         && (!p->two_underscores || ((s - orig_s) >= 2))
+         && strncmp(s, p->name, p->len) == 0)
+       {
+         return p->ret;
+       }
+    }
+  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 PROTO((void))
+choose_temp_base ()
 {
   char *base = getenv ("TMPDIR");
   int len;
@@ -388,16 +495,16 @@ main (argc, argv)
   FILE *outf;
   char *ld_file_name;
   char *c_file_name;
-  char *B_option;
   char *p;
   char *prefix;
-  char **c_argv                = (char **) xcalloc (sizeof (char *), argc+7);
-  char **c_ptr         = c_argv;
+  char **c_argv;
+  char **c_ptr;
   char **ld1_argv      = (char **) xcalloc (sizeof (char *), argc+2);
   char **ld1           = ld1_argv;
   char **ld2_argv      = (char **) xcalloc (sizeof (char *), argc+5);
   char **ld2           = ld2_argv;
   int first_file;
+  int num_c_args       = argc+7;
   int len;
   int clen;
 
@@ -406,6 +513,21 @@ main (argc, argv)
   vflag = 1;
 #endif
 
+  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'))
+         num_c_args++;
+
+       if (*q) q++;
+       p = q;
+      }
+
+  c_ptr = c_argv = (char **) xcalloc (sizeof (char *), num_c_args);
+
   if (argc < 2)
     fatal ("no arguments");
 
@@ -466,9 +588,7 @@ main (argc, argv)
 #endif
 
   ld_file_name = xcalloc (len + sizeof ("real-ld"), 1);
-  c_file_name  = xcalloc (clen + sizeof ("gcc"), 1);
   nm_file_name = xcalloc (len + sizeof ("gnm"), 1);
-  B_option     = xcalloc (len + sizeof ("-B"), 1);
 
   memcpy (ld_file_name, prefix, len);
   strcpy (ld_file_name + len, "real-ld");
@@ -486,23 +606,28 @@ main (argc, argv)
        }
     }
 
-  memcpy (c_file_name, prefix, len);
-  strcpy (c_file_name + len, "gcc");
-  if (access (c_file_name, X_OK) < 0)
+  c_file_name = getenv ("COLLECT_GCC");
+  if (c_file_name == 0 || c_file_name[0] != '/')
     {
-#ifdef STANDARD_BIN_PREFIX
-      strcpy (c_file_name, STANDARD_BIN_PREFIX);
-      strcat (c_file_name, "gcc");
+      c_file_name = xcalloc (clen + sizeof ("gcc"), 1);
+      memcpy (c_file_name, prefix, len);
+      strcpy (c_file_name + len, "gcc");
       if (access (c_file_name, X_OK) < 0)
-#endif
        {
-#ifdef STANDARD_EXEC_PREFIX
-         strcpy (c_file_name, STANDARD_EXEC_PREFIX);
+#ifdef STANDARD_BIN_PREFIX
+         strcpy (c_file_name, STANDARD_BIN_PREFIX);
          strcat (c_file_name, "gcc");
          if (access (c_file_name, X_OK) < 0)
 #endif
            {
-             strcpy (c_file_name, "gcc");
+#ifdef STANDARD_EXEC_PREFIX
+             strcpy (c_file_name, STANDARD_EXEC_PREFIX);
+             strcat (c_file_name, "gcc");
+             if (access (c_file_name, X_OK) < 0)
+#endif
+               {
+                 strcpy (c_file_name, "gcc");
+               }
            }
        }
     }
@@ -523,9 +648,6 @@ main (argc, argv)
        }
     }
 
-  strcpy (B_option, "-B");
-  strcpy (B_option + sizeof ("-B") - 1, prefix);
-
   *ld1++ = *ld2++ = "ld";
 
   /* Make temp file names. */
@@ -534,13 +656,21 @@ main (argc, argv)
   o_file = xcalloc (temp_filename_length + sizeof (".o"), 1);
   sprintf (c_file, "%s.c", temp_filename);
   sprintf (o_file, "%s.o", temp_filename);
-  *c_ptr++ = "gcc";
+  *c_ptr++ = c_file_name;
   *c_ptr++ = "-c";
   *c_ptr++ = "-o";
   *c_ptr++ = o_file;
 
+  /* !!! When GCC calls collect2,
+     it does not know whether it is calling collect2 or ld.
+     So collect2 cannot meaningfully understand any options
+     except those ld understands.
+     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. */
-  /* After the first file, put in the c++ rt0 */
+  /* After the first file, put in the c++ rt0.  */
+
   first_file = 1;
   while ((arg = *++argv) != (char *)0)
     {
@@ -559,22 +689,6 @@ main (argc, argv)
                }
              break;
 
-             /* pass -f<xxx>, -B<xxx>, -b<xxx>, -V<xxx>, and -m<xxx>
-                options to gcc.  This allows options to be passed
-                that affect search rules, and the size of pointers. */
-           case 'b':
-           case 'B':
-           case 'f':
-           case 'm':
-           case 'V':
-             if (arg[1] != '\0')
-               {
-                 ld1--;
-                 ld2--;
-                 *c_ptr++ = arg;
-               }
-             break;
-
            case 'o':
              outfile = (arg[2] == '\0') ? argv[1] : &arg[2];
              break;
@@ -599,13 +713,26 @@ main (argc, argv)
        }
     }
 
-  *c_ptr++ = B_option;
+  /* 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);
+
+       if (*q) q++;
+       p = q;
+      }
+
   *c_ptr++ = c_file;
   *c_ptr = *ld1 = *ld2 = (char *)0;
 
   if (vflag)
     {
-      fprintf (stderr, "GNU COLLECT2 version %s", version_string);
+      fprintf (stderr, "collect2 version %s", version_string);
 #ifdef TARGET_VERSION
       TARGET_VERSION;
 #endif
@@ -614,13 +741,31 @@ main (argc, argv)
 
   if (debug)
     {
-      fprintf (stderr, "prefix       = %s\n", prefix);
-      fprintf (stderr, "ld_file_name = %s\n", ld_file_name);
-      fprintf (stderr, "c_file_name  = %s\n", c_file_name);
-      fprintf (stderr, "nm_file_name = %s\n", nm_file_name);
-      fprintf (stderr, "B_option     = %s\n", B_option);
-      fprintf (stderr, "c_file       = %s\n", c_file);
-      fprintf (stderr, "o_file       = %s\n", o_file);
+      char *ptr;
+      fprintf (stderr, "prefix              = %s\n", prefix);
+      fprintf (stderr, "ld_file_name        = %s\n", ld_file_name);
+      fprintf (stderr, "c_file_name         = %s\n", c_file_name);
+      fprintf (stderr, "nm_file_name        = %s\n", nm_file_name);
+      fprintf (stderr, "c_file              = %s\n", c_file);
+      fprintf (stderr, "o_file              = %s\n", o_file);
+
+      ptr = getenv ("COLLECT_GCC_OPTIONS");
+      if (ptr)
+       fprintf (stderr, "COLLECT_GCC_OPTIONS = %s\n", ptr);
+
+      ptr = getenv ("COLLECT_GCC");
+      if (ptr)
+       fprintf (stderr, "COLLECT_GCC         = %s\n", ptr);
+
+      ptr = getenv ("COMPILER_PATH");
+      if (ptr)
+       fprintf (stderr, "COMPILER_PATH       = %s\n", ptr);
+
+      ptr = getenv ("LIBRARY_PATH");
+      if (ptr)
+       fprintf (stderr, "LIBRARY_PATH        = %s\n", ptr);
+
+      fprintf (stderr, "\n");
     }
 
   /* Load the program, searching all libraries.
@@ -688,21 +833,28 @@ do_wait (prog)
   wait (&status);
   if (status)
     {
-      int sig = WTERMSIG (status);
+      int sig = status & 0x7F;
       int ret;
 
       if (sig != -1 && sig != 0)
        {
+#ifdef NO_SYS_SIGLIST
+         error ("%s terminated with signal %d %s",
+                prog,
+                sig,
+                (status & 0200) ? ", core dumped" : "");
+#else
          error ("%s terminated with signal %d [%s]%s",
                 prog,
                 sig,
                 sys_siglist[sig],
                 (status & 0200) ? ", core dumped" : "");
+#endif
 
          my_exit (127);
        }
 
-      ret = WEXITSTATUS (status);
+      ret = ((status & 0xFF00) >> 8);
       if (ret != -1 && ret != 0)
        {
          error ("%s returned %d exit status", prog, ret);
@@ -720,8 +872,8 @@ fork_execute (prog, argv)
      char **argv;
 {
   int pid;
-  void (*int_handler) PROTO((int));
-  void (*quit_handler) PROTO((int));
+  void (*int_handler) ();
+  void (*quit_handler) ();
 
   if (vflag || debug)
     {
@@ -748,8 +900,8 @@ fork_execute (prog, argv)
       fatal_perror ("Execute %s", prog);
     }
 
-  int_handler  = (void (*)PROTO((int)))signal (SIGINT,  SIG_IGN);
-  quit_handler = (void (*)PROTO((int)))signal (SIGQUIT, SIG_IGN);
+  int_handler  = (void (*) ())signal (SIGINT,  SIG_IGN);
+  quit_handler = (void (*) ())signal (SIGQUIT, SIG_IGN);
 
   do_wait (prog);
 
@@ -832,18 +984,18 @@ write_c_file (stream, name)
 
   fprintf (stream, "typedef void entry_pt();\n\n");
     
-  write_list_with_asm (stream, "entry_pt ", constructors);
+  write_list_with_asm (stream, "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);
+  write_list (stream, "\t", constructors.first);
   fprintf (stream, "\t0\n};\n\n");
 
-  write_list_with_asm (stream, "entry_pt ", destructors);
+  write_list_with_asm (stream, "entry_pt ", destructors.first);
 
   fprintf (stream, "\nentry_pt * __DTOR_LIST__[] = {\n");
   fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number);
-  write_list (stream, "\t", destructors);
+  write_list (stream, "\t", destructors.first);
   fprintf (stream, "\t0\n};\n\n");
 
   fprintf (stream, "extern entry_pt __main;\n");
@@ -851,11 +1003,10 @@ write_c_file (stream, name)
 }
 
 \f
-#ifndef OBJECT_FORMAT_ROSE
+#ifdef OBJECT_FORMAT_NONE
 
-/* OSF/rose specific version to scan the name list of the loaded
-   program for the symbols g++ uses for static constructors and
-   destructors.
+/* 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
@@ -868,8 +1019,8 @@ scan_prog_file (prog_name, which_pass)
      char *prog_name;
      enum pass which_pass;
 {
-  void (*int_handler) PROTO((int));
-  void (*quit_handler) PROTO((int));
+  void (*int_handler) ();
+  void (*quit_handler) ();
   char *nm_argv[4];
   int pid;
   int argc = 0;
@@ -880,12 +1031,12 @@ scan_prog_file (prog_name, which_pass)
   if (which_pass != PASS_FIRST)
     return;
 
-  nm_argv[ argc++ ] = "nm";
+  nm_argv[argc++] = "nm";
   if (NM_FLAGS[0] != '\0')
-    nm_argv[ argc++ ] = NM_FLAGS;
+    nm_argv[argc++] = NM_FLAGS;
 
-  nm_argv[ argc++ ] = prog_name;
-  nm_argv[ argc++ ] = (char *)0;
+  nm_argv[argc++] = prog_name;
+  nm_argv[argc++] = (char *)0;
 
   if (pipe (pipe_fd) < 0)
     fatal_perror ("pipe");
@@ -932,8 +1083,8 @@ scan_prog_file (prog_name, which_pass)
     }
 
   /* Parent context from here on.  */
-  int_handler  = (void (*)PROTO((int)))signal (SIGINT,  SIG_IGN);
-  quit_handler = (void (*)PROTO((int)))signal (SIGQUIT, SIG_IGN);
+  int_handler  = (void (*) ())signal (SIGINT,  SIG_IGN);
+  quit_handler = (void (*) ())signal (SIGQUIT, SIG_IGN);
 
   if (close (pipe_fd[1]) < 0)
     fatal_perror ("Close (%d)", pipe_fd[1]);
@@ -945,8 +1096,7 @@ scan_prog_file (prog_name, which_pass)
   while (fgets (buf, sizeof buf, inf) != (char *)0)
     {
       int ch, ch2;
-      char *start;
-      char *end;
+      char *name, *end;
 
       /* If it contains a constructor or destructor name, add the name
         to the appropriate list. */
@@ -956,42 +1106,29 @@ scan_prog_file (prog_name, which_pass)
 
       if (ch == '\0' || ch == '\n')
        continue;
-
-      start = p;
-      while ((ch = *p) == '_') /* skip any extra '_' inserted */
-       p++;
-
-      for (end = p; (ch2 = *end) != '\0' && !isspace (ch2); end++)
-       ;
+  
+      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 != '|';
+          end++)
+       continue;
 
       *end = '\0';
-      if (ch == 'G')
+      switch (is_ctor_dtor (name))
        {
-         if (! strncmp (p, "GLOBAL_$I$", 10))
-           add_to_list (&constructors, p-1);
+       case 1:
+         add_to_list (&constructors, name);
+         break;
 
-         else if (! strncmp (p, "GLOBAL_$D$", 10))
-           add_to_list (&destructors, p-1);
+       case 2:
+         add_to_list (&destructors, name);
+         break;
 
-         else                          /* not a constructor or destructor */
-           continue;
+       default:                /* not a constructor or destructor */
+         continue;
        }
 
-      else if (ch == 's' && (p - start) >= 2)
-       {
-         if (! strncmp (p, "sti__", 5))
-           add_to_list (&constructors, p-2);
-
-         else if (! strncmp (p, "std__", 5))
-           add_to_list (&destructors, p-2);
-
-         else                          /* not a constructor or destructor */
-           continue;
-       }
-
-      else
-       continue;
-
       if (debug)
        fprintf (stderr, "\t%s\n", buf);
     }
@@ -1008,7 +1145,115 @@ scan_prog_file (prog_name, which_pass)
   signal (SIGQUIT, quit_handler);
 }
 
-#endif /* !OBJECT_FORMAT_ROSE */
+#endif /* OBJECT_FORMAT_NONE */
+
+\f
+/*
+ * COFF specific stuff.
+ */
+
+#ifdef OBJECT_FORMAT_COFF
+
+#if defined(EXTENDED_COFF)
+#   define GCC_SYMBOLS(X) (SYMHEADER(X).isymMax+SYMHEADER(X).iextMax)
+#   define GCC_SYMENT SYMR
+#   define GCC_OK_SYMBOL(X) ((X).st == stProc && (X).sc == scText)
+#   define GCC_SYMINC(X) (1)
+#   define GCC_SYMZERO(X) (SYMHEADER(X).isymMax)
+#else
+#   define GCC_SYMBOLS(X) (HEADER(ldptr).f_nsyms)
+#   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)))
+#   define GCC_SYMINC(X) ((X).n_numaux+1)
+#   define GCC_SYMZERO(X) 0
+#endif
+
+extern char *ldgetname ();
+
+/* COFF version to scan the name list of the loaded program for
+   the symbols g++ uses for static constructors and destructors.
+
+   The constructor table begins at __CTOR_LIST__ and contains a count
+   of the number of pointers (or -1 if the constructors are built in a
+   separate section by the linker), followed by the pointers to the
+   constructor functions, terminated with a null pointer.  The
+   destructor table has the same format, and begins at __DTOR_LIST__.  */
+
+static void
+scan_prog_file (prog_name, which_pass)
+     char *prog_name;
+     enum pass which_pass;
+{
+  LDFILE *ldptr;
+  int sym_index, sym_count;
+
+  if (which_pass != PASS_FIRST)
+    return;
+
+  if ((ldptr = ldopen (prog_name, ldptr)) == NULL)
+    fatal ("%s: can't open as COFF file", prog_name);
+      
+  if (!ISCOFF (HEADER(ldptr).f_magic))
+    fatal ("%s: not a COFF file", prog_name);
+
+  sym_count = GCC_SYMBOLS (ldptr);
+  sym_index = GCC_SYMZERO (ldptr);
+  while (sym_index < sym_count)
+    {
+      GCC_SYMENT symbol;
+
+      if (ldtbread (ldptr, sym_index, &symbol) <= 0)
+       break;
+      sym_index += GCC_SYMINC (symbol);
+
+      if (GCC_OK_SYMBOL (symbol))
+       {
+         char *name;
+
+         if ((name = ldgetname (ldptr, &symbol)) == NULL)
+           continue;           /* should never happen */
+
+#ifdef _AIX
+         /* All AIX function names begin with a dot. */
+         if (*name++ != '.')
+           continue;
+#endif
+
+         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 !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);
+#else
+         if (debug)
+           fprintf (stderr, "\tiss = %5d, value = %5d, index = %5d, name = %s\n",
+                    symbol.iss, symbol.value, symbol.index, name);
+#endif
+       }
+    }
+
+  (void) ldclose(ldptr);
+}
+
+#endif /* OBJECT_FORMAT_COFF */
 
 \f
 /*
@@ -1023,7 +1268,7 @@ typedef union load_union
 {
   ldc_header_t                 hdr;    /* common header */
   load_cmd_map_command_t       map;    /* map indexing other load cmds */
-  interpreter_command_t                iprtr;  /* interpereter pathname */
+  interpreter_command_t                iprtr;  /* interpreter pathname */
   strings_command_t            str;    /* load commands strings section */
   region_command_t             region; /* region load command */
   reloc_command_t              reloc;  /* relocation section */
@@ -1055,31 +1300,21 @@ struct file_info
   int  use_mmap;                       /* != 0 if mmap'ed */
 };
 
-extern int decode_mach_o_hdr           PROTO(( void *in_bufp,
-                                               size_t in_bufsize,
-                                               unsigned long hdr_version,
-                                               mo_header_t *headerp ));
+extern int decode_mach_o_hdr ();
 
-extern int encode_mach_o_hdr           PROTO(( mo_header_t *headerp,
-                                               void *out_bufp,
-                                               size_t out_bufsize ));
+extern int encode_mach_o_hdr ();
 
-static void bad_header                 PROTO(( int status ));
+static void bad_header ();
 
-static void print_header               PROTO(( mo_header_t *hdr_ptr ));
+static void print_header ();
 
-static void print_load_command         PROTO(( load_union_t *load_hdr,
-                                               size_t offset,
-                                               int number ));
+static void print_load_command ();
 
-static void add_func_table             PROTO(( mo_header_t *hdr_p,
-                                               load_all_t *load_array,
-                                               symbol_info_t *sym,
-                                               int type ));
+static void add_func_table ();
 
-static struct file_info        *read_file      PROTO(( char *, int, int ));
+static struct file_info        *read_file ();
 
-static void end_file                   PROTO(( struct file_info * ));
+static void end_file ();
 
 \f
 /* OSF/rose specific version to scan the name list of the loaded
@@ -1203,7 +1438,7 @@ scan_prog_file (prog_name, which_pass)
 
          if (debug)
            {
-             char *kind = "uknown";
+             char *kind = "unknown";
 
              switch (load_hdr->sym.symc_kind)
                {
@@ -1219,7 +1454,7 @@ scan_prog_file (prog_name, which_pass)
          if (load_hdr->sym.symc_kind != SYMC_DEFINED_SYMBOLS)
            continue;
 
-         str_sect = load_array[ load_hdr->sym.symc_strings_section ].section;
+         str_sect = load_array[load_hdr->sym.symc_strings_section].section;
          if (str_sect == (char *)0)
            fatal ("string section missing");
 
@@ -1231,50 +1466,37 @@ scan_prog_file (prog_name, which_pass)
            {
              symbol_info_t *sym = ((symbol_info_t *) load_cmd->section) + i;
              char *name = sym->si_name.symbol_name + str_sect;
-             char *name_start = name;
 
              if (name[0] != '_')
                continue;
 
-             while (*++name == '_')    /* skip any extra '_' inserted */
-               ;
-
              if (rw)
                {
-                 if (*name != 'm' || (name - name_start) < 2
-                     || strcmp (name, "main"))
+                 char *n = name;
+                 while (*n == '_')
+                   ++n;
+                 if (*n != 'm' || (n - name) < 2 || strcmp (n, "main"))
                    continue;
 
                  main_sym = sym;
                }
-
-             else if (*name == 'G')
-               {
-                 if (! strncmp (name, "GLOBAL_$I$", 10))
-                   add_to_list (&constructors, name_start);
-
-                 else if (! strncmp (name, "GLOBAL_$D$", 10))
-                   add_to_list (&destructors, name_start);
-
-                 else          /* not a constructor or destructor */
-                   continue;
-               }
-
-             else if (*name == 's' && (name - name_start) > 2)
+             else
                {
-                 if (! strncmp (name, "sti__", 5))
-                   add_to_list (&constructors, name_start);
-
-                 else if (! strncmp (name, "std__", 5))
-                   add_to_list (&destructors, name_start);
-
-                 else          /* not a constructor or destructor */
-                   continue;
+                 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;
+                   }
                }
 
-             else
-               continue;
-
              if (debug)
                fprintf (stderr, "\ttype = 0x%.4x, sc = 0x%.2x, flags = 0x%.8x, name = %.30s\n",
                         sym->si_type, sym->si_sc_type, sym->si_flags, name);
@@ -1369,7 +1591,7 @@ scan_prog_file (prog_name, which_pass)
 
 \f
 /* Add a function table to the load commands to call a function
-   on initition or termination of the process.  */
+   on initiation or termination of the process.  */
 
 static void
 add_func_table (hdr_p, load_array, sym, type)