home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1991 Free Software Foundation, Inc.
- * collect3.c - derived from collect2.c by Heinz Seidl (hgs@cygnus.com).
- */
-
- /*
- This file is part of GNU CC.
-
- GNU CC is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- 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. */
-
- /*
- C++ allows to initialize global variables with arbitrary expressions,
- in particular with constructors. This means, that arbitrary pieces of
- code have to be executed _before_ `main()' is called and that constructed
- objects must be destructed at the end of the program before `exit()' is
- called.
-
- For each file with global initialization gcc generates now initialization
- and finalization code:
-
- The initialization code has the label: `__GLOBAL_$I$<name>', where <name> is
- the name of the first variable to be initialized.
- The finitialization code has the label: `__GLOBAL_$D$<name>', where <name>
- is the name of the first variable to be destructed.
-
- Since the C runtime system (and the UNIX linkers) don't know about this kind
- of initialization, we have to deal with them:
-
- This program "collects" all the entrypoints for initialization and
- finalization code and associates them with the labels `__CTOR_LIST__' and
- `__DTOR_LIST__' respectively.
-
- Gcc generates code for the call to `main()' witch invokes the initialization
- and finalization code.
- */
-
-
- /*
- * The __C/DTOR_LIST__ have the folowing form:
- *
- * entry_pt * __C/DTOR_LIST__[] = {
- * _first_entry_point,
- * _second_entry_point,
- * ...
- * 0
- * }
- *
- * Both lists are in _proper_ order; i.e. the destructor list is in reverse
- * order of the constructor list.
- *
- * In case OLD_FORMAT is defined, init.c understands the format generated by
- * gld 1.x and used by gnulib3.
- *
- * The order is determined by the order of the .o files on the command line
- * and how the linker arranges them in the output file.
- * It is expected that the linker arranges the con/destructors in reverse
- * order as the command line.
- * There is no predicable order for files from archives.
- */
-
- static char * rcsId = "$Id: collect3.c,v 1.2 1991/10/03 00:37:07 hgs Exp $";
-
- #if defined (__GNUC__)
- #define alloca __builtin_alloca
- #else
- #define alloca malloc
- #endif
-
- #include "config.h"
-
- /* This means no additional `_' is prepended;
- but have at least one `_' at the beginning */
- #ifdef NO_UNDERSCORES
- #define CTOR_MARKER_NAME "_GLOBAL_$I$"
- #define DTOR_MARKER_NAME "_GLOBAL_$D$"
- #define CDTOR_MARKER_LEN 11
- #define FUNCTION_LIST_ADDR "_function_list_addr"
- #define FUNCTION_LIST_ADDR_LEN 19
- #else
- #define CTOR_MARKER_NAME "__GLOBAL_$I$"
- #define DTOR_MARKER_NAME "__GLOBAL_$D$"
- #define CDTOR_MARKER_LEN 12
- #define FUNCTION_LIST_ADDR "__function_list_addr"
- #define FUNCTION_LIST_ADDR_LEN 20
- #endif
-
- #include <stdio.h>
-
- #define USAGE() do fprintf( stderr, \
- "Usage: %s <link-command options>" ## \
- "[-- [-t] [-d tmp_dir] [-g gcc-path]]", \
- argv[0]); \
- while(0);
-
- #define GREP_CMD " grep -v TOR_LIST__"
- #define NM_CMD " nm -pg"
-
- /* convert empty string into blank (stupidity of ?printf) */
- #define S(str) ((str && *str) ? str : " ")
-
- extern char *mktemp (char *template);
-
- static void error( const char * msg, int line );
- #define ERROR(msg) error( msg, __LINE__)
-
- #ifndef PREFIX
- #define PREFIX "/usr/unsupported"
- #endif
-
- #define const static
- /* causes strange bugs */
- const char * TMP_DIR = "/usr/tmp";
- const char * AOUTXXX = "AOUTXXXXXX";
- const char * CDTORXXX = "CDTORXXXXXX";
- const char * GCC_FLAGS = "-g -ftraditional";
- const char * GCC = PREFIX "/bin/gcc";
- #undef const
-
- static char * prog_name = NULL;
-
- /* Linked lists of constructor and destructor names.
- */
- struct id
- {
- char *name;
- struct id *next;
- };
-
- /* if we link ccrt0 to an object we always need the C/DTOR_LISTS even if they are empty */
- static int need_cdtor_list = 0;
-
- main (int argc, char *argv[])
- {
- char /*const causes strange errors*/* tmp_dir = TMP_DIR;
- char CDTOR_filename_c[BUFSIZ], CDTOR_filename_o[BUFSIZ], buf[BUFSIZ];
- char AOUT_filename[BUFSIZ];
- FILE * pipe_in;
- char * outfile = "a.out";
- char * arg, ldargs1[BUFSIZ*2], ldargs2[BUFSIZ*2], cmd[BUFSIZ*4];
- char * s = ldargs1;
- char * debug_str = NULL; /* or `set -x; ' */
- int no_rm = 0;
- char /* const */* gcc = GCC;
- int ret = 0;
-
- ldargs1[0] = '\0'; ldargs2[0] = '\0';
-
- prog_name = argv[0];
- /* Parse arguments for the linker
- */
- while (arg = *++argv)
- {
- if (! strcmp (arg, "--"))
- {
- /* parse the options for collect
- */
- while (arg = *++argv)
- {
- switch ( (int) arg[1])
- {
- case 'v':
- debug_str = "set -x;";
- tmp_dir = ".";
- break;
- case 'd':
- tmp_dir = *++argv;
- break;
- case 'g':
- gcc = *++argv;
- break;
- case 'r':
- no_rm = 1;
- tmp_dir = ".";
- break;
- default:
- USAGE();
- exit(1);
- }
- }
- break; /* get out of arg parsing loop */
- }
-
-
- /* remove output file from command line
- */
- if (! strcmp (arg, "-o"))
- {
- outfile = *++argv;
- continue;
- }
-
- /* Split the arguments after *rt0.o and before the first .o file
- */
- if ( !strcmp (arg + strlen(arg) -2, ".o") )
- if (! (strlen( arg) >= 5 && !strcmp (arg+strlen(arg)-5, "rt0.o")) )
- s = ldargs2;
-
- strcat (s , " '"); strcat (s, arg); strcat (s, "'");
- }
-
- /* Make temp file names.
- */
- if (debug_str)
- {
- tmp_dir = ".";
- sprintf( AOUT_filename, "%s", AOUTXXX);
- (void) mktemp (AOUT_filename);
- }
- else
- sprintf( AOUT_filename, "%s", outfile); /* we reuse the outfile */
-
- sprintf( buf, "%s/%s", tmp_dir, CDTORXXX);
- (void) mktemp (buf);
- sprintf (CDTOR_filename_c, "%s.c", buf);
- sprintf (CDTOR_filename_o, "%s.o", buf);
-
-
-
- /* Load the program, searching all libraries.
- * (The introduction of shared libraries fucked the -r option of
- * the SunOS linker; therefore we link twice; unless we don't have
- * de/constructors).
- */
- if ( debug_str)
- sprintf (cmd, "%s ld -o %s %s %s",
- S(debug_str), AOUT_filename, S(ldargs1), S(ldargs2));
- else
- sprintf (cmd, "ld -o %s %s %s 2>&1 |" GREP_CMD,
- AOUT_filename, S(ldargs1), S(ldargs2));
- system( cmd);
-
- /* Examine the namelist with nm and search it for static constructors
- * and destructors to call.
- * Write the constructor and destructor tables to a .c file.
- */
- sprintf (cmd, "%s " NM_CMD " %s", S(debug_str), AOUT_filename);
- if (! (pipe_in = popen (cmd, "r"))) ERROR( "popen failed");
-
- ret = write_CDTOR_list (pipe_in, CDTOR_filename_c);
-
- if (pclose (pipe_in)) ERROR( "pclose failed");
-
- if ( ret == 0 && ! need_cdtor_list) exit(0); /* no de/constructors */
-
- /* Compile the constructor and destructor tables.
- */
- if ( debug_str )
- sprintf (cmd, "%s %s -v -c %s -o %s %s",
- S(debug_str), gcc, GCC_FLAGS,
- CDTOR_filename_o, CDTOR_filename_c);
- else
- sprintf (cmd,"%s -c %s -o %s %s",
- gcc, GCC_FLAGS, CDTOR_filename_o, CDTOR_filename_c);
- system( cmd);
-
- /* Link the tables in with the rest of the program.
- */
- sprintf (cmd, "%s ld -o %s %s %s %s",
- S(debug_str), outfile, S(ldargs1), CDTOR_filename_o,
- S(ldargs2));
- system( cmd);
-
- if ( ! debug_str && ! no_rm)
- {
- unlink (CDTOR_filename_c);
- unlink (CDTOR_filename_o);
- }
-
- exit(0);
- }
-
- int write_CDTOR_list (FILE * pipe_in, char * CDTOR_filename_c)
- /*
- * Scan the name list of the loaded program for the symbols g++ uses
- * for static constructors and destructors. Write their addresses
- * into tables which __main() and exit() will call.
- * returns 0 iff no de/constructors - otherwise > 0
- */
- {
- register char *p;
- char buf[BUFSIZ];
- struct id *newid;
- FILE * CDTOR_file;
-
- struct id *constructors = 0;
- struct id *destructors = 0, *d_anchor = 0;
- #ifdef OLD_FORMAT
- int nb_constructors = 0, nb_destructors = 0;
- #endif
-
- while (! feof (pipe_in))
- {
- /* read a line and strip trailing newline */
- fgets (buf, sizeof buf, pipe_in);
- p = buf + strlen( buf) - 1;
- if ( *p == '\n') *p = '\0';
-
- /* If it contains a constructor or destructor name, add the name
- * to the appropriate list.
- */
- for (p = buf; *p && *p != '_'; p++);
-
- if (! strncmp (p, CTOR_MARKER_NAME, CDTOR_MARKER_LEN))
- {
- newid = alloca (sizeof *newid);
- newid->name = alloca (strlen (p) + 1);
- #ifdef NO_UNDERSCORES
- strcpy (newid->name, p);
- #else
- strcpy (newid->name, p+1);
- #endif
- newid->next = constructors;
- constructors = newid;
- #ifdef OLD_FORMAT
- nb_constructors ++;
- #endif
- }
- else if (! strncmp (p, DTOR_MARKER_NAME, CDTOR_MARKER_LEN))
- {
- newid = alloca (sizeof *newid);
- newid->name = alloca (strlen (p) + 1);
- #ifdef NO_UNDERSCORES
- strcpy (newid->name, p);
- #else
- strcpy (newid->name, p+1);
- #endif
- #ifdef OLD_FORMAT
- newid->next = destructors;
- destructors = newid;
- nb_destructors ++;
- #else
- newid->next = 0;
- if( !d_anchor)
- { d_anchor = destructors = newid; }
- else
- {
- destructors->next = newid;
- destructors = newid;
- }
- #endif
- }
- else if ( ! need_cdtor_list &&
- /* this shows we have ccrt0 and need the C/DTOR_LISTs */
- (! strncmp (p, FUNCTION_LIST_ADDR, FUNCTION_LIST_ADDR_LEN)))
- need_cdtor_list ++;
- }
-
- if ( ! need_cdtor_list && constructors == 0 && destructors == 0 ) return 0;
-
- if (! (CDTOR_file = fopen (CDTOR_filename_c, "w")))
- ERROR( "fopen failed");
-
- /* Write the tables as C code */
- fprintf (CDTOR_file, "typedef void entry_pt();\n\n");
-
- write_list (CDTOR_file, "entry_pt ", constructors, ";\n");
-
- fprintf (CDTOR_file, "\nentry_pt * __CTOR_LIST__[] = {\n");
- #ifdef OLD_FORMAT
- fprintf (CDTOR_file, "\t(entry_pt *) %d,\n", nb_constructors);
- write_list (CDTOR_file, "\t", constructors, ",\n");
- #else
- write_list (CDTOR_file, "\t", constructors, ",\n");
- #endif
- fprintf (CDTOR_file, "\t0\n};\n\n");
-
- #ifdef OLD_FORMAT
- write_list (CDTOR_file, "entry_pt ", destructors, ";\n");
- #else
- write_list (CDTOR_file, "entry_pt ", d_anchor, ";\n");
- #endif
-
- fprintf (CDTOR_file, "\nentry_pt * __DTOR_LIST__[] = {\n");
- #ifdef OLD_FORMAT
- fprintf (CDTOR_file, "\t(entry_pt *) %d,\n", nb_destructors);
- write_list (CDTOR_file, "\t", destructors, ",\n");
- #else
- write_list (CDTOR_file, "\t", d_anchor, ",\n");
- #endif
- fprintf (CDTOR_file, "\t0\n};\n\n");
-
- if (fclose (CDTOR_file))
- ERROR( "fclose failed");
-
- return 1;
- }
-
-
- write_list ( FILE *CDTOR_file, char * prefix, struct id *list, char * suffix)
- /*
- * Write `prefix', the names on list LIST, `suffix'.
- */
- {
- if (! list)
- return;
- write_list ( CDTOR_file, prefix, list->next, suffix);
- fprintf ( CDTOR_file, "%s%s%s", prefix, list->name, suffix);
- }
-
-
- static void error( const char * msg, int line )
- {
- static char buf[BUFSIZ];
- sprintf( buf, "%s: %s at %d", prog_name, S(msg), line);
- perror( buf);
- exit( 1);
- }
-
-
- /* FIXME: the -r option should be enabled (maybe with a flag) on certain machines */
- /* FIXME: no fixed size arrays should be used, but xmalloc (see collect-osf) */
- /* FIXME: check why const does not work */
- /* FIXME: encapsulate prototypes */
- /* FIXME: make all external interface names configureable */
-