#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>
+#ifdef NO_WAIT_H
#include <sys/wait.h>
+#endif
+
+#ifndef errno
+extern int errno;
+#endif
#define COLLECT
#include "config.h"
#ifndef __STDC__
-#include "gvarargs.h"
#define generic char
-#define PROTO(x) ()
#define const
#else
-#include "stdarg.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
#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. */
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 */
static int rflag; /* true if -r */
+static int strip_flag; /* true if -s */
static int debug; /* true if -debug */
static char *c_file; /* <xxx>.c for constructor/destructor list. */
static char *o_file; /* <xxx>.o for constructor/destructor list. */
static char *nm_file_name; /* pathname of nm */
+static char *strip_file_name; /* pathname of strip */
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 ();
+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 *
+my_strerror (e)
int e;
{
extern char *sys_errlist[];
sprintf (buffer, "Unknown error %d", e);
return buffer;
}
-
-#endif
-
\f
/* Delete tempfiles and exit function. */
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);
}
\f
-#ifndef __STDC__
-
/* Die when sys call fails. */
-/*VARARGS*/
-static void
-fatal_perror (va_alist)
-{
- char *string;
- va_list vptr;
- int e = errno;
-
- va_start (vptr);
- string = va_arg (vptr, char *);
- fprintf (stderr, "collect: ");
- vfprintf (stderr, string, vptr);
- fprintf (stderr, ": %s\n", strerror (e));
- va_end (vptr);
- my_exit (1);
-}
-
-/* Just die. */
-
-/*VARARGS*/
-static void
-fatal (va_alist)
-{
- char *string;
- va_list vptr;
-
- va_start (vptr);
- string = va_arg (vptr, char *);
- fprintf (stderr, "collect: ");
- vfprintf (stderr, string, vptr);
- fprintf (stderr, "\n");
- va_end (vptr);
- my_exit (1);
-}
-
-/* Write error message. */
-
-/*VARARGS*/
static void
-error (va_alist)
+fatal_perror (string, arg1, arg2, arg3)
+ char *string;
{
- char *string;
- va_list vptr;
-
- va_start (vptr);
- string = va_arg (vptr, char *);
- fprintf (stderr, "collect: ");
- vfprintf (stderr, string, vptr);
- fprintf (stderr, "\n");
- va_end (vptr);
-}
-
-#else
-
-static void
-fatal_perror (char *string, ...)
-{
- va_list vptr;
int e = errno;
- va_start (vptr, string);
fprintf (stderr, "collect: ");
- vfprintf (stderr, string, vptr);
- fprintf (stderr, ": %s\n", strerror (e));
- va_end (vptr);
+ fprintf (stderr, string, arg1, arg2, arg3);
+ fprintf (stderr, ": %s\n", my_strerror (e));
my_exit (1);
}
/* Just die. */
static void
-fatal (char *string, ...)
+fatal (string, arg1, arg2, arg3)
+ char *string;
{
- va_list vptr;
-
- va_start (vptr, string);
fprintf (stderr, "collect: ");
- vfprintf (stderr, string, vptr);
+ fprintf (stderr, string, arg1, arg2, arg3);
fprintf (stderr, "\n");
- va_end (vptr);
my_exit (1);
}
/* Write error message. */
static void
-error (char *string, ...)
+error (string, arg1, arg2, arg3, arg4)
+ char *string;
{
- va_list vptr;
-
- va_start (vptr, string);
fprintf (stderr, "collect: ");
- vfprintf (stderr, string, vptr);
+ fprintf (stderr, string, arg1, arg2, arg3, arg4);
fprintf (stderr, "\n");
- va_end (vptr);
}
-#endif
-\f
/* In case obstack is linked in, and abort is defined to fancy_abort,
provide a default entry. */
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;
- fatal ("Out of memory.");
+ fatal ("out of memory");
return (generic *)0;
}
generic *
xmalloc (size)
- size_t size;
+ int size;
{
- generic *ptr = malloc (size);
+ generic *ptr = (generic *) malloc (size);
if (ptr)
return ptr;
- fatal ("Out of memory.");
+ fatal ("out of memory");
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);
+ bcopy (input, output, size);
+ output[size] = 0;
+ 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;
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;
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')
+ 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");
signal (SIGSEGV, handler);
signal (SIGBUS, handler);
- /* Try to discover a valid linker/assembler/nm to use. */
+ /* Try to discover a valid linker/assembler/nm/strip to use. */
len = strlen (argv[0]);
prefix = (char *)0;
if (len >= sizeof ("ld")-1)
clen = sizeof (STANDARD_BIN_PREFIX) - 1;
#endif
+#ifdef STANDARD_EXEC_PREFIX
+ if (clen < sizeof (STANDARD_EXEC_PREFIX) - 1)
+ clen = sizeof (STANDARD_EXEC_PREFIX) - 1;
+#endif
+
+ /* Allocate enough string space for the longest possible pathnames. */
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);
+ strip_file_name = xcalloc (len + sizeof ("gstrip"), 1);
- memcpy (ld_file_name, prefix, len);
+ /* Determine the full path name of the ld program to use. */
+ bcopy (prefix, ld_file_name, len);
strcpy (ld_file_name + len, "real-ld");
if (access (ld_file_name, X_OK) < 0)
{
#ifdef REAL_LD_FILE_NAME
ld_file_name = REAL_LD_FILE_NAME;
#else
- ld_file_name = (access ("/usr/bin/ld", X_OK) == 0) ? "/usr/bin/ld" : "/bin/ld";
+ ld_file_name = (access ("/usr/bin/ld", X_OK) == 0
+ ? "/usr/bin/ld" : "/bin/ld");
#endif
}
}
- memcpy (c_file_name, prefix, len);
- strcpy (c_file_name + len, "gcc");
- if (access (c_file_name, X_OK) < 0)
+ /* Determine the full path name of the C compiler to use. */
+ 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);
+ bcopy (prefix, c_file_name, 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");
+ }
}
}
}
- memcpy (nm_file_name, prefix, len);
+ /* Determine the full path name of the nm to use. */
+ bcopy (prefix, nm_file_name, len);
strcpy (nm_file_name + len, "nm");
if (access (nm_file_name, X_OK) < 0)
{
#ifdef REAL_NM_FILE_NAME
nm_file_name = REAL_NM_FILE_NAME;
#else
- nm_file_name = (access ("/usr/bin/nm", X_OK) == 0) ? "/usr/bin/nm" : "/bin/nm";
+ nm_file_name = (access ("/usr/bin/nm", X_OK) == 0
+ ? "/usr/bin/nm" : "/bin/nm");
#endif
}
}
- strcpy (B_option, "-B");
- strcpy (B_option + sizeof ("-B") - 1, prefix);
+ /* Determine the full pathname of the strip to use. */
+ bcopy (prefix, strip_file_name, len);
+ strcpy (strip_file_name + len, "strip");
+ if (access (strip_file_name, X_OK) < 0)
+ {
+ strcpy (strip_file_name + len, "gstrip");
+ if (access (strip_file_name, X_OK) < 0)
+ {
+ free (strip_file_name);
+#ifdef REAL_STRIP_FILE_NAME
+ strip_file_name = REAL_STRIP_FILE_NAME;
+#else
+ strip_file_name = (access ("/usr/bin/strip", X_OK) == 0
+ ? "/usr/bin/strip" : "/bin/strip");
+#endif
+ }
+ }
*ld1++ = *ld2++ = "ld";
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)
{
}
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;
rflag = 1;
break;
+ case 's':
+ if (arg[2] == '\0')
+ {
+ /* We must strip after the nm run, otherwise C++ linking
+ won't work. Thus we strip in the second ld run, or
+ else with strip if there is no second ld run. */
+ strip_flag = 1;
+ ld1--;
+ }
+ break;
+
case 'v':
if (arg[2] == '\0')
vflag = 1;
}
}
- *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
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.
}
if (constructors.number == 0 && destructors.number == 0)
- return 0;
+ {
+ /* Strip now if it was requested on the command line. */
+ if (strip_flag)
+ {
+ char **strip_argv = (char **) xcalloc (sizeof (char *), 3);
+ strip_argv[0] = "strip";
+ strip_argv[1] = outfile;
+ strip_argv[2] = (char *) 0;
+ fork_execute (strip_file_name, strip_argv);
+ }
+ return 0;
+ }
outf = fopen (c_file, "w");
if (outf == (FILE *)0)
- fatal_perror ("Can't write %s", c_file);
+ fatal_perror ("%s", c_file);
write_c_file (outf, c_file);
if (fclose (outf))
- fatal_perror ("Can't close %s", c_file);
+ fatal_perror ("closing %s", c_file);
if (debug)
{
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);
char **argv;
{
int pid;
- void (*int_handler) PROTO((int));
- void (*quit_handler) PROTO((int));
+ void (*int_handler) ();
+ void (*quit_handler) ();
if (vflag || debug)
{
if (pid == 0) /* child context */
{
execvp (prog, argv);
- fatal_perror ("Execute %s", prog);
+ fatal_perror ("executing %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);
fprintf (stream, "typedef void entry_pt();\n\n");
- write_list_with_asm (stream, "entry_pt ", constructors);
+ 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);
+ 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, "extern 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");
}
\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
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;
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");
{
/* setup stdout */
if (dup2 (pipe_fd[1], 1) < 0)
- fatal_perror ("Dup2 (%d, 1)", pipe_fd[1]);
+ fatal_perror ("dup2 (%d, 1)", pipe_fd[1]);
if (close (pipe_fd[0]) < 0)
- fatal_perror ("Close (%d)", pipe_fd[0]);
+ fatal_perror ("close (%d)", pipe_fd[0]);
if (close (pipe_fd[1]) < 0)
- fatal_perror ("Close (%d)", pipe_fd[1]);
+ fatal_perror ("close (%d)", pipe_fd[1]);
execv (nm_file_name, nm_argv);
- fatal_perror ("Execute %s", nm_file_name);
+ fatal_perror ("executing %s", nm_file_name);
}
/* 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]);
+ fatal_perror ("close (%d)", pipe_fd[1]);
if (debug)
fprintf (stderr, "\nnm output with constructors/destructors.\n");
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. */
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);
}
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)
+# define GCC_CHECK_HDR(X) (PSYMTAB(X) != 0)
+#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
+# define GCC_CHECK_HDR(X) (1)
+#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);
+
+ if (GCC_CHECK_HDR (ldptr))
+ {
+ 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
/*
{
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 */
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
prog_fd = open (prog_name, (rw) ? O_RDWR : O_RDONLY);
if (prog_fd < 0)
- fatal_perror ("Can't read %s", prog_name);
+ fatal_perror ("can't read %s", prog_name);
obj_file = read_file (prog_name, prog_fd, rw);
obj = obj_file->start;
|| hdr.moh_cpu_subtype != OUR_CPU_SUBTYPE
|| hdr.moh_vendor_type != OUR_VENDOR_TYPE)
{
- fatal ("incompatibilities exist between object file & expected values.");
+ fatal ("incompatibilities between object file & expected values");
}
#endif
if (rw)
{
load_union_t *ptr = (load_union_t *) xmalloc (load_hdr->hdr.ldci_cmd_size);
- memcpy (ptr, load_hdr, load_hdr->hdr.ldci_cmd_size);
+ bcopy (load_hdr, ptr, load_hdr->hdr.ldci_cmd_size);
load_hdr = ptr;
/* null out old command map, because we will rewrite at the end. */
if (debug)
{
- char *kind = "uknown";
+ char *kind = "unknown";
switch (load_hdr->sym.symc_kind)
{
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");
{
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')
+ else
{
- 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;
+ 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 if (*name == 's' && (name - name_start) > 2)
- {
- 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;
- }
-
- 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);
}
if (symbol_load_cmds == 0)
- fatal ("no symbol table found.");
+ fatal ("no symbol table found");
/* Update the program file now, rewrite header and load commands. At present,
we assume that there is enough space after the last load command to insert
size_t size;
if (cmd_strings == -1)
- fatal ("no cmd_strings found.");
+ fatal ("no cmd_strings found");
+
+ /* Add __main to initializer list.
+ If we are building a program instead of a shared library, don't
+ do anything, since in the current version, you cannot do mallocs
+ and such in the constructors. */
- /* Add __main to initializer list. */
- 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);
if (debug)
if (debug)
print_load_command (load_hdr, offset, i);
- memcpy (obj + offset, load_hdr, size);
+ bcopy (load_hdr, obj + offset, size);
offset += size;
}
}
end_file (obj_file);
if (close (prog_fd))
- fatal_perror ("Can't close %s", prog_name);
+ fatal_perror ("closing %s", prog_name);
if (debug)
fprintf (stderr, "\n");
\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)