that can be traversed by C++ initialization and finalization
routines.
- Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1993, 1994, 1995, 1996 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.
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 "config.h"
#include <sys/types.h>
#include <stdio.h>
#include <ctype.h>
#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;
#endif
-#if defined(bsd4_4) || defined(__NetBSD__)
+#ifndef HAVE_STRERROR
+#if defined(bsd4_4)
extern const char *const sys_errlist[];
#else
extern char *sys_errlist[];
#endif
extern int sys_nerr;
-
-#define COLLECT
-
-#include "config.h"
-
-#ifndef __STDC__
-#define generic char
-#define const
-
#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
-/* 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
#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
#define MY_ISCOFF(X) ISCOFF (X)
#endif
+#ifdef XCOFF_DEBUGGING_INFO
+#define XCOFF_SCAN_LIBS
+#endif
+
#endif /* OBJECT_FORMAT_COFF */
#ifdef OBJECT_FORMAT_ROSE
/* 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 niether. */
+ must define both, or neither. */
#ifndef NAME__MAIN
#define NAME__MAIN "__main"
#define SYMBOL__MAIN __main
#endif
-#if defined (LDD_SUFFIX) || defined (SUNOS4_SHARED_LIBRARIES)
+#if defined (LDD_SUFFIX) || SUNOS4_SHARED_LIBRARIES || defined(XCOFF_SCAN_LIBS)
#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
{
enum pass {
PASS_FIRST, /* without constructors */
+ PASS_OBJ, /* individual objects */
PASS_LIB, /* looking for shared libraries */
PASS_SECOND /* with constructors linked in */
};
#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 */
-static int debug; /* true if -debug */
+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. */
+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 */
static char *ldd_file_name; /* pathname of ldd (or equivalent) */
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 */
+static struct head exports; /* list of exported symbols */
+
+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 ();
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
char *name; /* Name of this list (used in config stuff) */
};
-static void my_exit PROTO((int));
+void collect_exit PROTO((int));
+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 *));
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 write_list PROTO((FILE *, char *, struct id *));
static void write_list_with_asm PROTO((FILE *, char *, struct id *));
static void write_c_file PROTO((FILE *, char *));
+static void write_export_file PROTO((FILE *));
static void scan_prog_file PROTO((char *, enum pass));
static void scan_libraries PROTO((char *));
-generic *xcalloc ();
-generic *xmalloc ();
+char *xcalloc ();
+char *xmalloc ();
extern char *index ();
extern char *rindex ();
+extern void free ();
\f
#ifdef NO_DUP2
int
\f
/* Delete tempfiles and exit function. */
-static void
-my_exit (status)
+void
+collect_exit (status)
int status;
{
if (c_file != 0 && c_file[0])
if (o_file != 0 && o_file[0])
maybe_unlink (o_file);
+ if (export_file != 0 && export_file[0])
+ maybe_unlink (export_file);
+
+ if (ldout != 0 && ldout[0])
+ {
+ dump_file (ldout);
+ maybe_unlink (ldout);
+ }
+
if (status != 0 && output_file != 0 && output_file[0])
maybe_unlink (output_file);
}
\f
-/* Die when sys call fails. */
+/* Die when sys call fails. */
-static void
+void
fatal_perror (string, arg1, arg2, arg3)
char *string, *arg1, *arg2, *arg3;
{
fprintf (stderr, "collect2: ");
fprintf (stderr, string, arg1, arg2, arg3);
fprintf (stderr, ": %s\n", my_strerror (e));
- my_exit (1);
+ collect_exit (1);
}
-/* Just die. */
+/* Just die. */
-static void
+void
fatal (string, arg1, arg2, arg3)
char *string, *arg1, *arg2, *arg3;
{
fprintf (stderr, "collect2: ");
fprintf (stderr, string, arg1, arg2, arg3);
fprintf (stderr, "\n");
- my_exit (1);
+ collect_exit (1);
}
/* Write error message. */
-static void
+void
error (string, arg1, arg2, arg3, arg4)
char *string, *arg1, *arg2, *arg3, *arg4;
{
if (o_file != 0 && o_file[0])
maybe_unlink (o_file);
+ 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);
}
\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. */
return output;
}
\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);
+ }
+}
+\f
/* Decide whether the given symbol is:
a constructor (1), a destructor (2), or neither (0). */
}
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. */
/* 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)
char *p = getenv (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)
+ 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;
+
+ add_prefix (pprefix, nstore);
+ if (*endp == 0)
+ break;
+ endp = startp = endp + 1;
}
+ else
+ endp++;
}
}
\f
-/* Main program. */
+/* Main program. */
int
main (argc, argv)
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 *gstrip_suffix = "gstrip";
char *full_gstrip_suffix = gstrip_suffix;
char *arg;
- FILE *outf;
+ FILE *outf, *exportf;
char *ld_file_name;
- char *c_file_name;
char *collect_name;
char *collect_names;
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;
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);
+ temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0);
+ current_demangling_style = gnu_demangling;
/* We must check that we do not call ourselves in an infinite
recursion loop. We append the name used for us to the COLLECT_NAMES
ld_file_name = find_a_file (&path, REAL_LD_FILE_NAME);
if (ld_file_name == 0)
#endif
-#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'. */
+ /* 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, real_ld_suffix);
- if (ld_file_name == 0)
- ld_file_name = find_a_file (&path, full_real_ld_suffix);
+ 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)
*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"));
+ 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);
+ sprintf (export_file, "%s.x", temp_filename);
*c_ptr++ = c_file_name;
*c_ptr++ = "-c";
*c_ptr++ = "-o";
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;
break;
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':
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
break;
}
}
- else if (first_file
- && (p = rindex (arg, '.')) != (char *)0
+ else if ((p = rindex (arg, '.')) != (char *) 0
&& (strcmp (p, ".o") == 0 || strcmp (p, ".a") == 0))
{
- first_file = 0;
- /* place o_file BEFORE this argument! */
- ld2--;
- *ld2++ = o_file;
- *ld2++ = arg;
+ 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;
}
}
p = q;
}
- /* Tell the linker that we have initializer and finalizer functions. */
- if (shared_obj)
- {
-#ifdef LD_INIT_SWITCH
- *ld2++ = LD_INIT_SWITCH;
- *ld2++ = "_GLOBAL__DI";
+#ifdef COLLECT_EXPORT_LIST
+ /* The AIX linker will discard static constructors in object files if
+ nothing else in the file is referenced, so look at them first. */
+ while (object_lst < object)
+ scan_prog_file (*object_lst++, PASS_OBJ);
+
+ {
+ char *buf = alloca (strlen (export_file) + 5);
+ sprintf (buf, "-bE:%s", export_file);
+ *ld1++ = buf;
+ *ld2++ = buf;
+ 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
-#ifdef LD_FINI_SWITCH
- *ld2++ = LD_FINI_SWITCH;
- *ld2++ = "_GLOBAL__DD";
-#endif
- }
*c_ptr++ = c_file;
- *c_ptr = *ld1 = *ld2 = (char *)0;
+ *object = *c_ptr = *ld1 = (char *) 0;
if (vflag)
{
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. */
- fork_execute ("ld", ld1_argv);
+ collect_execute ("ld", ld1_argv, ldout);
+ do_wait ("ld");
+ dump_file (ldout);
+ unlink (ldout);
- /* If -r, don't build the constructor or destructor list, just return now. */
- if (rflag)
+ /* If -r or they'll be run via some other method, don't build the
+ 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. */
+
scan_prog_file (output_file, PASS_FIRST);
#ifdef SCAN_LIBRARIES
strip_argv[2] = (char *) 0;
fork_execute ("strip", strip_argv);
}
+
+#ifdef COLLECT_EXPORT_LIST
+ maybe_unlink (export_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);
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);
fork_execute ("ld", ld2_argv);
maybe_unlink (c_file);
maybe_unlink (o_file);
+ maybe_unlink (export_file);
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;
(status & 0200) ? ", core dumped" : "");
#endif
- my_exit (127);
+ collect_exit (127);
}
if (WIFEXITED (status))
- {
- int ret = WEXITSTATUS (status);
- if (ret != 0)
- {
- error ("%s returned %d exit status", prog, ret);
- my_exit (ret);
- }
- }
+ 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;
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");
if (pid == 0) /* child context */
{
+ if (redir)
+ {
+ unlink (redir);
+ if (freopen (redir, "a", stdout) == NULL)
+ fatal_perror ("redirecting stdout");
+ if (freopen (redir, "a", stderr) == NULL)
+ fatal_perror ("redirecting stderr");
+ }
+
execvp (argv[0], argv);
fatal_perror ("executing %s", prog);
}
+}
+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. */
char *name;
{
char *prefix, *p, *q;
- char *initname, *fininame;
/* Figure out name of output_file, stripping off .so version. */
p = rindex (output_file, '/');
fprintf (stream, "\tp = ctors + %d;\n", constructors.number);
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);
}
fprintf (stream, "}\n");
- fprintf (stream, "void _GLOBAL__DI() {\n\t%s();\n}\n", initname);
- fprintf (stream, "void _GLOBAL__DD() {\n\t%s();\n}\n", fininame);
-
- free (initname);
- free (fininame);
+ 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. */
+/* Write the constructor/destructor tables. */
static void
write_c_file_glob (stream, name)
FILE *stream;
char *name;
{
- if (shared_obj)
- write_c_file_stat (stream, name);
- else
+#ifndef LD_INIT_SWITCH
+ if (! shared_obj)
write_c_file_glob (stream, name);
+ else
+#endif
+ write_c_file_stat (stream, name);
+}
+
+static void
+write_export_file (stream)
+ FILE *stream;
+{
+ struct id *list = exports.first;
+ for (; list; list = list->next)
+ fprintf (stream, "%s\n", list->name);
}
\f
#ifdef OBJECT_FORMAT_NONE
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. */
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");
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] == ' ')
#endif
}
-#ifdef SUNOS4_SHARED_LIBRARIES
+#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
#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 */
unsigned object; /* address of memory mapped file */
close (fp);
}
+/* Helpers for locatelib. */
+
+static char *libname;
+
+static int
+libselect (d)
+ struct direct *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;
+{
+ 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]))
+ {
+ ++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. */
if (*q == ':')
{
*q++ = 0;
- *pp++ = p;
+ *pp++ = q;
}
}
/* built in directories are /lib, /usr/lib, and /usr/local/lib */
*pp++ = "/usr/local/lib";
*pp = 0;
}
+ libname = name;
for (pp = l; *pp != 0 ; pp++)
{
- sprintf (buf, "%s/%s", *pp, name);
- if (access (buf, R_OK) == 0)
+ 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);
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;
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++)
LDFILE *ldptr = NULL;
int sym_index, sym_count;
- if (which_pass != PASS_FIRST)
+ if (which_pass != PASS_FIRST && which_pass != PASS_OBJ)
return;
if ((ldptr = ldopen (prog_name, ldptr)) == NULL)
if ((name = ldgetname (ldptr, &symbol)) == NULL)
continue; /* should never happen */
-#ifdef _AIX
- /* All AIX function names begin with a dot. */
- if (*name++ != '.')
- continue;
+#ifdef XCOFF_DEBUGGING_INFO
+ /* All AIX function names have a duplicate entry beginning
+ with a dot. */
+ if (*name == '.')
+ ++name;
#endif
switch (is_ctor_dtor (name))
{
case 1:
add_to_list (&constructors, name);
+ if (which_pass == PASS_OBJ)
+ add_to_list (&exports, name);
break;
case 2:
add_to_list (&destructors, name);
+ if (which_pass == PASS_OBJ)
+ add_to_list (&exports, name);
break;
default: /* not a constructor or destructor */
(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
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 *));
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;
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);
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;
}
}
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;
int number;
{
mo_long_t type = load_hdr->hdr.ldci_cmd_type;
- char *type_str = (char *)0;
+ char *type_str = (char *) 0;
switch (type)
{
(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)
bad_header (status)
int status;
{
- char *msg = (char *)0;
+ char *msg = (char *) 0;
switch (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);
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
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 */