-/* Collect static initialization info into data structures
- that can be traversed by C++ initialization and finalization
- routines.
-
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+/* Collect static initialization info into data structures that can be
+ traversed by C++ initialization and finalization routines.
+ Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
Contributed by Chris Smith (csmith@convex.com).
Heavily modified by Michael Meissner (meissner@cygnus.com),
Per Bothner (bothner@cygnus.com), and John Gilmore (gnu@cygnus.com).
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 <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;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-#if !defined (__STDC__) && !defined (const)
-#define const
-#endif
-
#ifdef USG
#define vfork fork
#endif
-/* Add prototype support. */
-#ifndef PROTO
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define PROTO(ARGS) ARGS
-#else
-#define PROTO(ARGS) ()
-#endif
-#endif
-
#ifndef R_OK
#define R_OK 4
#define W_OK 2
#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
#define SYMBOL__MAIN __main
#endif
-#if defined (LDD_SUFFIX) || SUNOS4_SHARED_LIBRARIES
+#if defined (LDD_SUFFIX) || SUNOS4_SHARED_LIBRARIES || defined(XCOFF_SCAN_LIBS)
#define SCAN_LIBRARIES
#endif
int do_collecting = 0;
#endif
\f
-/* Linked lists of constructor and destructor names. */
+/* Linked lists of constructor and destructor names. */
struct id
{
static int temp_filename_length; /* Length of temp_filename */
static char *temp_filename; /* Base of temp filenames */
-static char *c_file; /* <xxx>.c for constructor/destructor list. */
-static char *o_file; /* <xxx>.o for constructor/destructor list. */
-static char *export_file; /* <xxx>.x for AIX export list. */
-static int auto_export = 1; /* true if exporting everything. */
+static char *c_file; /* <xxx>.c for constructor/destructor list. */
+static char *o_file; /* <xxx>.o for constructor/destructor list. */
+static char *export_file; /* <xxx>.x for AIX export list. */
char *ldout; /* File for ld errors. */
static char *output_file; /* Output file for ld. */
static char *nm_file_name; /* pathname of nm */
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
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 *));
}
\f
-/* Die when sys call fails. */
+/* Die when sys call fails. */
void
fatal_perror (string, arg1, arg2, arg3)
fprintf (stderr, "collect2: ");
fprintf (stderr, string, arg1, arg2, arg3);
fprintf (stderr, ": %s\n", my_strerror (e));
- collect_exit (1);
+ collect_exit (FATAL_EXIT_CODE);
}
-/* Just die. */
+/* Just die. */
void
fatal (string, arg1, arg2, arg3)
fprintf (stderr, "collect2: ");
fprintf (stderr, string, arg1, arg2, arg3);
fprintf (stderr, "\n");
- collect_exit (1);
+ collect_exit (FATAL_EXIT_CODE);
}
/* Write error message. */
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);
}
return ptr;
fatal ("out of memory");
- return (char *)0;
+ return (char *) 0;
}
char *
return ptr;
fatal ("out of memory");
- return (char *)0;
+ return (char *) 0;
}
char *
break;
putc (c, stderr);
}
+ fclose (stream);
}
\f
/* Decide whether the given symbol is:
}
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)
}
}
\f
-/* Main program. */
+/* Main program. */
int
main (argc, argv)
vflag = 1;
#endif
+#ifndef DEFAULT_A_OUT_NAME
output_file = "a.out";
+#else
+ output_file = DEFAULT_A_OUT_NAME;
+#endif
obstack_begin (&temporary_obstack, 0);
obstack_begin (&permanent_obstack, 0);
*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"));
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;
-#ifdef COLLECT_EXPORT_LIST
- case 'b':
- if ((!strncmp (arg, "-bE:", 4)
- || !strncmp (arg, "-bexport:", 9))
- && strcmp (arg, "-bexport:/usr/lib/libg.exp"))
- auto_export = 0;
- break;
-#endif
-
case 'l':
if (first_file)
{
break;
}
}
- else if ((p = rindex (arg, '.')) != (char *)0
+ else if ((p = rindex (arg, '.')) != (char *) 0
&& (strcmp (p, ".o") == 0 || strcmp (p, ".a") == 0))
{
if (first_file)
*ld1++ = buf;
*ld2++ = buf;
exportf = fopen (export_file, "w");
- if (exportf == (FILE *)0)
+ if (exportf == (FILE *) 0)
fatal_perror ("%s", export_file);
write_export_file (exportf);
if (fclose (exportf))
#endif
*c_ptr++ = c_file;
- *object = *c_ptr = *ld1 = (char *)0;
+ *object = *c_ptr = *ld1 = (char *) 0;
if (vflag)
{
unlink (ldout);
/* If -r or they'll be run via some other method, don't build the
- constructor or destructor list, just return now. */
+ constructor or destructor list, just return now. */
if (rflag || ! do_collecting)
return 0;
/* Examine the namelist with nm and search it for static constructors
and destructors to call.
- Write the constructor and destructor tables to a .s file and reload. */
+ Write the constructor and destructor tables to a .s file and reload. */
scan_prog_file (output_file, PASS_FIRST);
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);
*ld2++ = LD_FINI_SWITCH;
*ld2++ = fininame;
#endif
- *ld2 = (char*)0;
+ *ld2 = (char*) 0;
#ifdef COLLECT_EXPORT_LIST
if (shared_obj)
add_to_list (&exports, "_GLOBAL__DI");
add_to_list (&exports, "_GLOBAL__DD");
exportf = fopen (export_file, "w");
- if (exportf == (FILE *)0)
+ if (exportf == (FILE *) 0)
fatal_perror ("%s", export_file);
write_export_file (exportf);
if (fclose (exportf))
}
/* 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);
}
\f
-/* Wait for a process to finish, and exit if a non-zero status is found. */
+/* Wait for a process to finish, and exit if a non-zero status is found. */
int
collect_wait (prog)
(status & 0200) ? ", core dumped" : "");
#endif
- collect_exit (127);
+ collect_exit (FATAL_EXIT_CODE);
}
if (WIFEXITED (status))
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");
}
}
-/* Write the constructor/destructor tables. */
+/* Write the constructor/destructor tables. */
static void
write_c_file_glob (stream, name)
FILE *stream;
char *name;
{
+ fprintf (stream, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
#ifndef LD_INIT_SWITCH
if (! shared_obj)
write_c_file_glob (stream, name);
else
#endif
write_c_file_stat (stream, name);
+ fprintf (stream, "#ifdef __cplusplus\n}\n#endif\n");
}
static void
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] == ' ')
#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 */
return (strncmp (libname, d->d_name, strlen (libname)) == 0);
}
-/* If one file has an additional numeric extention past LIBNAME, then put
+/* 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.
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++)
#ifdef XCOFF_DEBUGGING_INFO
/* All AIX function names have a duplicate entry beginning
- with a dot. */
+ with a dot. */
if (*name == '.')
++name;
#endif
break;
default: /* not a constructor or destructor */
- if (which_pass == PASS_OBJ && auto_export)
- add_to_list (&exports, name);
continue;
}
(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);