diff options
author | obrien <obrien@FreeBSD.org> | 1999-08-26 09:30:50 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 1999-08-26 09:30:50 +0000 |
commit | 0bedf4fb30066e5e1d4342a1d3914dae7d37cba7 (patch) | |
tree | 68d8110b41afd0ebbf39167b1a4918eea667a7c5 /contrib/gcc/collect2.c | |
parent | d4db5fb866b7ad5216abd5047774a3973b9901a9 (diff) | |
download | FreeBSD-src-0bedf4fb30066e5e1d4342a1d3914dae7d37cba7.zip FreeBSD-src-0bedf4fb30066e5e1d4342a1d3914dae7d37cba7.tar.gz |
Virgin import of gcc from EGCS 1.1.2
Diffstat (limited to 'contrib/gcc/collect2.c')
-rw-r--r-- | contrib/gcc/collect2.c | 1375 |
1 files changed, 804 insertions, 571 deletions
diff --git a/contrib/gcc/collect2.c b/contrib/gcc/collect2.c index 30fb49d..4fcbe73 100644 --- a/contrib/gcc/collect2.c +++ b/contrib/gcc/collect2.c @@ -1,8 +1,6 @@ -/* 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-97, 1998 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). @@ -25,67 +23,30 @@ 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 <errno.h> +#include "system.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" - -#ifndef errno -extern int errno; -#endif - -#ifndef HAVE_STRERROR -#if defined(bsd4_4) -extern const char *const sys_errlist[]; -#else -extern char *sys_errlist[]; -#endif -extern int sys_nerr; -#else -char *strerror(); +#include "gansidecl.h" +#ifdef __CYGWIN32__ +#include <process.h> #endif /* Obstack allocation and deallocation routines. */ #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 X_OK 1 -#endif - #ifndef WIFSIGNALED #define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f) #endif @@ -99,18 +60,12 @@ char *strerror(); #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 *make_temp_file PROTO ((char *)); /* 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. Likewise, the names of - the utilities aren't correct for a cross-compiler; we have to hope that + the utilities are not correct for a cross-compiler; we have to hope that cross-versions are in the proper directories. */ #ifdef CROSS_COMPILE @@ -123,10 +78,10 @@ char *strerror(); #undef REAL_STRIP_FILE_NAME #endif -/* If we can't use a special method, use the ordinary one: +/* If we cannot 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. */ + but that is not quite as unpleasant as special headers. */ #if !defined (OBJECT_FORMAT_COFF) && !defined (OBJECT_FORMAT_ROSE) #define OBJECT_FORMAT_NONE @@ -158,10 +113,6 @@ char *strerror(); #define MY_ISCOFF(X) ISCOFF (X) #endif -#ifdef XCOFF_DEBUGGING_INFO -#define XCOFF_SCAN_LIBS -#endif - #endif /* OBJECT_FORMAT_COFF */ #ifdef OBJECT_FORMAT_ROSE @@ -200,7 +151,7 @@ char *strerror(); #define SYMBOL__MAIN __main #endif -#if defined (LDD_SUFFIX) || SUNOS4_SHARED_LIBRARIES || defined(XCOFF_SCAN_LIBS) +#if defined (LDD_SUFFIX) || SUNOS4_SHARED_LIBRARIES #define SCAN_LIBRARIES #endif @@ -210,7 +161,7 @@ int do_collecting = 1; int do_collecting = 0; #endif -/* Linked lists of constructor and destructor names. */ +/* Linked lists of constructor and destructor names. */ struct id { @@ -236,7 +187,7 @@ enum pass { }; #ifndef NO_SYS_SIGLIST -#ifndef DONT_DECLARE_SYS_SIGLIST +#ifndef SYS_SIGLIST_DECLARED extern char *sys_siglist[]; #endif #endif @@ -245,27 +196,39 @@ extern char *version_string; int vflag; /* true if -v */ static int rflag; /* true if -r */ static int strip_flag; /* true if -s */ +#ifdef COLLECT_EXPORT_LIST +static int export_flag; /* true if -bE */ +static int aix64_flag; /* true if -b64 */ +#endif 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 *export_file; /* <xxx>.x for AIX export list. */ +static char *c_file; /* <xxx>.c for constructor/destructor list. */ +static char *o_file; /* <xxx>.o for constructor/destructor list. */ +#ifdef COLLECT_EXPORT_LIST +static char *export_file; /* <xxx>.x for AIX export list. */ +static char *import_file; /* <xxx>.p for AIX import list. */ +#endif char *ldout; /* File for ld errors. */ static char *output_file; /* Output file for ld. */ static char *nm_file_name; /* pathname of nm */ +#ifdef LDD_SUFFIX static char *ldd_file_name; /* pathname of ldd (or equivalent) */ +#endif 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 */ +#ifdef COLLECT_EXPORT_LIST static struct head exports; /* list of exported symbols */ +static struct head imports; /* list of imported symbols */ +static struct head undefined; /* list of undefined symbols */ +#endif +static struct head frame_tables; /* list of frame unwind info tables */ struct obstack temporary_obstack; struct obstack permanent_obstack; @@ -274,17 +237,20 @@ char * temporary_firstobj; /* Defined in the automatically-generated underscore.c. */ extern int prepends_underscore; -extern char *getenv (); extern char *mktemp (); extern FILE *fdopen (); +#ifndef GET_ENVIRONMENT +#define GET_ENVIRONMENT(ENV_VALUE,ENV_NAME) ENV_VALUE = getenv (ENV_NAME) +#endif + /* Structure to hold all the directories in which to search for files to execute. */ 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 @@ -294,13 +260,19 @@ struct path_prefix char *name; /* Name of this list (used in config stuff) */ }; -void collect_exit PROTO((int)); -void collect_execute PROTO((char *, char **, char *)); -void dump_file PROTO((char *)); +#ifdef COLLECT_EXPORT_LIST +/* Lists to keep libraries to be scanned for global constructors/destructors. */ +static struct head libs; /* list of libraries */ +static struct path_prefix cmdline_lib_dirs; /* directories specified with -L */ +static struct path_prefix libpath_lib_dirs; /* directories in LIBPATH */ +static struct path_prefix *libpaths[3] = {&cmdline_lib_dirs, + &libpath_lib_dirs, NULL}; +static char *libexts[3] = {"a", "so", NULL}; /* possible library extentions */ +#endif + +static char *my_strerror PROTO((int)); 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 *)); @@ -310,18 +282,30 @@ static void fork_execute PROTO((char *, char **)); static void maybe_unlink PROTO((char *)); static void add_to_list PROTO((struct head *, char *)); static void write_list PROTO((FILE *, char *, struct id *)); +#ifdef COLLECT_EXPORT_LIST +static void dump_list PROTO((FILE *, char *, struct id *)); +#endif +#if 0 +static void dump_prefix_list PROTO((FILE *, char *, struct prefix_list *)); +#endif 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)); +#ifdef SCAN_LIBRARIES static void scan_libraries PROTO((char *)); +#endif +#ifdef COLLECT_EXPORT_LIST +static int is_in_list PROTO((char *, struct id *)); +static void write_export_file PROTO((FILE *)); +static void write_import_file PROTO((FILE *)); +static char *resolve_lib_name PROTO((char *)); +static int use_import_list PROTO((char *)); +static int ignore_library PROTO((char *)); +#endif char *xcalloc (); char *xmalloc (); -extern char *index (); -extern char *rindex (); -extern void free (); #ifdef NO_DUP2 int @@ -345,7 +329,7 @@ dup2 (oldfd, newfd) } #endif -char * +static char * my_strerror (e) int e; { @@ -379,9 +363,14 @@ collect_exit (status) if (o_file != 0 && o_file[0]) maybe_unlink (o_file); +#ifdef COLLECT_EXPORT_LIST if (export_file != 0 && export_file[0]) maybe_unlink (export_file); + if (import_file != 0 && import_file[0]) + maybe_unlink (import_file); +#endif + if (ldout != 0 && ldout[0]) { dump_file (ldout); @@ -395,7 +384,7 @@ collect_exit (status) } -/* Die when sys call fails. */ +/* Die when sys call fails. */ void fatal_perror (string, arg1, arg2, arg3) @@ -406,10 +395,10 @@ 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) @@ -418,7 +407,7 @@ 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. */ @@ -455,6 +444,14 @@ handler (signo) if (ldout != 0 && ldout[0]) maybe_unlink (ldout); +#ifdef COLLECT_EXPORT_LIST + if (export_file != 0 && export_file[0]) + maybe_unlink (export_file); + + if (import_file != 0 && import_file[0]) + maybe_unlink (import_file); +#endif + signal (signo, SIG_DFL); kill (getpid (), signo); } @@ -469,7 +466,7 @@ xcalloc (size1, size2) return ptr; fatal ("out of memory"); - return (char *)0; + return (char *) 0; } char * @@ -481,7 +478,7 @@ xmalloc (size) return ptr; fatal ("out of memory"); - return (char *)0; + return (char *) 0; } char * @@ -514,6 +511,39 @@ savestring (input, size) output[size] = 0; return output; } + +/* Parse a reasonable subset of shell quoting syntax. */ + +static char * +extract_string (pp) + char **pp; +{ + char *p = *pp; + int backquote = 0; + int inside = 0; + + for (;;) + { + char c = *p; + if (c == '\0') + break; + ++p; + if (backquote) + obstack_1grow (&temporary_obstack, c); + else if (! inside && c == ' ') + break; + else if (! inside && c == '\\') + backquote = 1; + else if (c == '\'') + inside = !inside; + else + obstack_1grow (&temporary_obstack, c); + } + + obstack_1grow (&temporary_obstack, '\0'); + *pp = p; + return obstack_finish (&temporary_obstack); +} void dump_file (name) @@ -528,7 +558,7 @@ dump_file (name) { int c; while (c = getc (stream), - c != EOF && (isalnum (c) || c == '_' || c == '$' || c == '.')) + c != EOF && (ISALNUM (c) || c == '_' || c == '$' || c == '.')) obstack_1grow (&temporary_obstack, c); if (obstack_object_size (&temporary_obstack) > 0) { @@ -570,6 +600,7 @@ dump_file (name) break; putc (c, stderr); } + fclose (stream); } /* Decide whether the given symbol is: @@ -590,17 +621,20 @@ is_ctor_dtor (s) #ifdef NO_DOT_IN_LABEL { "GLOBAL__I_", sizeof ("GLOBAL__I_")-1, 1, 0 }, { "GLOBAL__D_", sizeof ("GLOBAL__D_")-1, 2, 0 }, + { "GLOBAL__F_", sizeof ("GLOBAL__F_")-1, 5, 0 }, #else { "GLOBAL_.I.", sizeof ("GLOBAL_.I.")-1, 1, 0 }, { "GLOBAL_.D.", sizeof ("GLOBAL_.D.")-1, 2, 0 }, + { "GLOBAL_.F.", sizeof ("GLOBAL_.F.")-1, 5, 0 }, #endif #else { "GLOBAL_$I$", sizeof ("GLOBAL_$I$")-1, 1, 0 }, { "GLOBAL_$D$", sizeof ("GLOBAL_$D$")-1, 2, 0 }, + { "GLOBAL_$F$", sizeof ("GLOBAL_$F$")-1, 5, 0 }, #endif { "GLOBAL__FI_", sizeof ("GLOBAL__FI_")-1, 3, 0 }, { "GLOBAL__FD_", sizeof ("GLOBAL__FD_")-1, 4, 0 }, -#ifdef CFRONT_LOSSAGE /* Don't collect cfront initialization functions. +#ifdef CFRONT_LOSSAGE /* Do not collect cfront initialization functions. cfront has its own linker procedure to collect them; if collect2 gets them too, they get collected twice when the cfront procedure is run and the compiler used @@ -628,42 +662,6 @@ is_ctor_dtor (s) } return 0; } - - -/* 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); -} /* Routine to add variables to the environment. */ @@ -730,52 +728,10 @@ static struct path_prefix cpath, path; static char *target_machine = TARGET_MACHINE; #endif -/* Names under which we were executed. Never return one of those files in our - searches. */ - -static struct path_prefix our_file_names; - -/* Determine if STRING is in PPREFIX. - - This utility is currently only used to look up file names. Prefix lists - record directory names. This matters to us because the latter has a - trailing slash, so I've added a flag to handle both. */ - -static int -is_in_prefix_list (pprefix, string, filep) - struct path_prefix *pprefix; - char *string; - int filep; -{ - struct prefix_list *pl; - - if (filep) - { - int len = strlen (string); - - for (pl = pprefix->plist; pl; pl = pl->next) - { - if (strncmp (pl->prefix, string, len) == 0 - && strcmp (pl->prefix + len, "/") == 0) - return 1; - } - } - else - { - for (pl = pprefix->plist; pl; pl = pl->next) - { - if (strcmp (pl->prefix, string) == 0) - return 1; - } - } - - return 0; -} - /* 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) @@ -786,6 +742,9 @@ find_a_file (pprefix, name) struct prefix_list *pl; int len = pprefix->max_len + strlen (name) + 1; + if (debug) + fprintf (stderr, "Looking for '%s'\n", name); + #ifdef EXECUTABLE_SUFFIX len += strlen (EXECUTABLE_SUFFIX); #endif @@ -794,35 +753,48 @@ find_a_file (pprefix, name) /* Determine the filename to execute (special case for absolute paths). */ - if (*name == '/') + if (*name == '/' +#ifdef DIR_SEPARATOR + || (DIR_SEPARATOR == '\\' && name[1] == ':' + && (name[2] == DIR_SEPARATOR || name[2] == '/')) +#endif + ) { if (access (name, X_OK) == 0) { strcpy (temp, name); + + if (debug) + fprintf (stderr, " - found: absolute path\n"); + return temp; } + + if (debug) + fprintf (stderr, " - failed to locate using absolute path\n"); } else for (pl = pprefix->plist; pl; pl = pl->next) { strcpy (temp, pl->prefix); strcat (temp, name); - if (! is_in_prefix_list (&our_file_names, temp, 1) - /* This is a kludge, but there seems no way around it. */ - && strcmp (temp, "./ld") != 0 - && access (temp, X_OK) == 0) + + if (access (temp, X_OK) == 0) return temp; #ifdef EXECUTABLE_SUFFIX /* Some systems have a suffix for executable files. So try appending that. */ strcat (temp, EXECUTABLE_SUFFIX); - if (! is_in_prefix_list (&our_file_names, temp, 1) - && access (temp, X_OK) == 0) + + if (access (temp, X_OK) == 0) return temp; #endif } + if (debug && pprefix->plist == NULL) + fprintf (stderr, " - failed: no entries in prefix list\n"); + free (temp); return 0; } @@ -870,7 +842,8 @@ prefix_from_env (env, pprefix) char *env; struct path_prefix *pprefix; { - char *p = getenv (env); + char *p; + GET_ENVIRONMENT (p, env); if (p) prefix_from_string (p, pprefix); @@ -884,6 +857,9 @@ prefix_from_string (p, pprefix) char *startp, *endp; char *nstore = (char *) xmalloc (strlen (p) + 3); + if (debug) + fprintf (stderr, "Convert string '%s' into prefixes, separator = '%c'\n", p, PATH_SEPARATOR); + startp = endp = p; while (1) { @@ -902,6 +878,9 @@ prefix_from_string (p, pprefix) else nstore[endp-startp] = 0; + if (debug) + fprintf (stderr, " - add prefix: %s\n", nstore); + add_prefix (pprefix, nstore); if (*endp == 0) break; @@ -912,7 +891,7 @@ prefix_from_string (p, pprefix) } } -/* Main program. */ +/* Main program. */ int main (argc, argv) @@ -922,7 +901,6 @@ main (argc, argv) char *ld_suffix = "ld"; char *full_ld_suffix = ld_suffix; char *real_ld_suffix = "real-ld"; - char *full_real_ld_suffix = real_ld_suffix; char *collect_ld_suffix = "collect-ld"; char *nm_suffix = "nm"; char *full_nm_suffix = nm_suffix; @@ -937,10 +915,12 @@ main (argc, argv) char *gstrip_suffix = "gstrip"; char *full_gstrip_suffix = gstrip_suffix; char *arg; - FILE *outf, *exportf; + FILE *outf; +#ifdef COLLECT_EXPORT_LIST + FILE *exportf; + FILE *importf; +#endif char *ld_file_name; - char *collect_name; - char *collect_names; char *p; char **c_argv; char **c_ptr; @@ -951,75 +931,44 @@ main (argc, argv) char **object_lst = (char **) xcalloc (sizeof (char *), argc); char **object = object_lst; int first_file; - int num_c_args = argc+7; + int num_c_args = argc+9; #ifdef DEBUG debug = 1; - vflag = 1; #endif + /* Parse command line early for instances of -debug. This allows + the debug flag to be set before functions like find_a_file() + are called. */ + { + int i; + + for (i = 1; argv[i] != NULL; i ++) + if (! strcmp (argv[i], "-debug")) + debug = 1; + vflag = debug; + } + +#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 - environment variable. - - In practice, collect will rarely invoke itself. This can happen now - that we are no longer called gld. A perfect example is when running - gcc in a build directory that has been installed. When looking for - ld's, we'll find our installed version and believe that's the real ld. */ - - /* We must also append COLLECT_NAME to COLLECT_NAMES to watch for the - previous version of collect (the one that used COLLECT_NAME and only - handled two levels of recursion). If we don't we may mutually recurse - forever. This can happen (I think) when bootstrapping the old version - and a new one is installed (rare, but we should handle it). - ??? Hopefully references to COLLECT_NAME can be removed at some point. */ - - collect_name = (char *) getenv ("COLLECT_NAME"); - collect_names = (char *) getenv ("COLLECT_NAMES"); - - p = (char *) xmalloc (strlen ("COLLECT_NAMES=") - + (collect_name ? strlen (collect_name) + 1 : 0) - + (collect_names ? strlen (collect_names) + 1 : 0) - + strlen (argv[0]) + 1); - strcpy (p, "COLLECT_NAMES="); - if (collect_name != 0) - sprintf (p + strlen (p), "%s%c", collect_name, PATH_SEPARATOR); - if (collect_names != 0) - sprintf (p + strlen (p), "%s%c", collect_names, PATH_SEPARATOR); - strcat (p, argv[0]); - putenv (p); - - prefix_from_env ("COLLECT_NAMES", &our_file_names); - - /* Set environment variable COLLECT_NAME to our name so the previous version - of collect won't find us. If it does we'll mutually recurse forever. - This can happen when bootstrapping the new version and an old version is - installed. - ??? Hopefully this bit of code can be removed at some point. */ - - p = xmalloc (strlen ("COLLECT_NAME=") + strlen (argv[0]) + 1); - sprintf (p, "COLLECT_NAME=%s", argv[0]); - putenv (p); - - 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; - } + current_demangling_style = gnu_demangling; + p = getenv ("COLLECT_GCC_OPTIONS"); + while (p && *p) + { + char *q = extract_string (&p); + if (*q == '-' && (q[1] == 'm' || q[1] == 'f')) + num_c_args++; + } + obstack_free (&temporary_obstack, temporary_firstobj); + ++num_c_args; c_ptr = c_argv = (char **) xcalloc (sizeof (char *), num_c_args); @@ -1054,7 +1003,7 @@ main (argc, argv) #ifdef CROSS_COMPILE /* If we look for a program in the compiler directories, we just use the short name, since these directories are already system-specific. - But it we look for a took in the system directories, we need to + But it we look for a program in the system directories, we need to qualify the program name with the target machine. */ full_ld_suffix @@ -1063,12 +1012,6 @@ main (argc, argv) strcat (full_ld_suffix, "-"); strcat (full_ld_suffix, ld_suffix); - full_real_ld_suffix - = xcalloc (strlen (real_ld_suffix) + strlen (target_machine) + 2, 1); - strcpy (full_real_ld_suffix, target_machine); - strcat (full_real_ld_suffix, "-"); - strcat (full_real_ld_suffix, real_ld_suffix); - #if 0 full_gld_suffix = xcalloc (strlen (gld_suffix) + strlen (target_machine) + 2, 1); @@ -1131,18 +1074,6 @@ main (argc, argv) if (ld_file_name == 0) ld_file_name = find_a_file (&path, full_ld_suffix); - /* If we've invoked ourselves, try again with LD_FILE_NAME. */ - - if (collect_names != 0) - { - if (ld_file_name != 0) - { - argv[0] = ld_file_name; - execvp (argv[0], argv); - } - fatal ("cannot find `ld'"); - } - #ifdef REAL_NM_FILE_NAME nm_file_name = find_a_file (&path, REAL_NM_FILE_NAME); if (nm_file_name == 0) @@ -1198,21 +1129,47 @@ main (argc, argv) *ld1++ = *ld2++ = ld_file_name; - /* Make temp file names. */ - choose_temp_base (); - 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); + /* Make temp file names. */ + c_file = make_temp_file (".c"); + o_file = make_temp_file (".o"); +#ifdef COLLECT_EXPORT_LIST + export_file = make_temp_file (".x"); + import_file = make_temp_file (".p"); +#endif + ldout = make_temp_file (".ld"); *c_ptr++ = c_file_name; + *c_ptr++ = "-x"; + *c_ptr++ = "c"; *c_ptr++ = "-c"; *c_ptr++ = "-o"; *c_ptr++ = o_file; +#ifdef COLLECT_EXPORT_LIST + /* Generate a list of directories from LIBPATH. */ + prefix_from_env ("LIBPATH", &libpath_lib_dirs); + /* Add to this list also two standard directories where + AIX loader always searches for libraries. */ + add_prefix (&libpath_lib_dirs, "/lib"); + add_prefix (&libpath_lib_dirs, "/usr/lib"); +#endif + + /* Get any options that the upper GCC wants to pass to the sub-GCC. + + AIX support needs to know if -shared has been specified before + parsing commandline arguments. */ + + p = getenv ("COLLECT_GCC_OPTIONS"); + while (p && *p) + { + char *q = extract_string (&p); + if (*q == '-' && (q[1] == 'm' || q[1] == 'f')) + *c_ptr++ = obstack_copy0 (&permanent_obstack, q, strlen (q)); + if (strncmp (q, "-shared", sizeof ("-shared") - 1) == 0) + shared_obj = 1; + } + obstack_free (&temporary_obstack, temporary_firstobj); + *c_ptr++ = "-fno-exceptions"; + /* !!! When GCC calls collect2, it does not know whether it is calling collect2 or ld. So collect2 cannot meaningfully understand any options @@ -1220,11 +1177,11 @@ main (argc, argv) 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; @@ -1232,11 +1189,21 @@ main (argc, argv) { switch (arg[1]) { +#ifdef COLLECT_EXPORT_LIST + /* We want to disable automatic exports on AIX when user + explicitly puts an export list in command line */ + case 'b': + if (arg[2] == 'E' || strncmp (&arg[2], "export", 6) == 0) + export_flag = 1; + if (arg[2] == '6' && arg[3] == '4') + aix64_flag = 1; + break; +#endif + case 'd': if (!strcmp (arg, "-debug")) { - debug = 1; - vflag = 1; + /* Already parsed. */ ld1--; ld2--; } @@ -1251,7 +1218,31 @@ main (argc, argv) *ld2++ = o_file; *ld2++ = arg; } +#ifdef COLLECT_EXPORT_LIST + { + /* Resolving full library name. */ + char *s = resolve_lib_name (arg+2); + + /* If we will use an import list for this library, + we should exclude it from ld args. */ + if (use_import_list (s)) + { + ld1--; + ld2--; + } + + /* Saving a full library name. */ + add_to_list (&libs, s); + } +#endif + break; + +#ifdef COLLECT_EXPORT_LIST + /* Saving directories where to search for libraries. */ + case 'L': + add_prefix (&cmdline_lib_dirs, arg+2); break; +#endif case 'o': if (arg[2] == '\0') @@ -1269,7 +1260,7 @@ main (argc, argv) 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 + will not work. Thus we strip in the second ld run, or else with strip if there is no second ld run. */ strip_flag = 1; ld1--; @@ -1282,8 +1273,9 @@ main (argc, argv) break; } } - else if ((p = rindex (arg, '.')) != (char *)0 - && (strcmp (p, ".o") == 0 || strcmp (p, ".a") == 0)) + else if ((p = rindex (arg, '.')) != (char *) 0 + && (strcmp (p, ".o") == 0 || strcmp (p, ".a") == 0 + || strcmp (p, ".so") == 0)) { if (first_file) { @@ -1300,47 +1292,71 @@ main (argc, argv) } if (p[1] == 'o') *object++ = arg; +#ifdef COLLECT_EXPORT_LIST + /* libraries can be specified directly, i.e. without -l flag. */ + else + { + /* If we will use an import list for this library, + we should exclude it from ld args. */ + if (use_import_list (arg)) + { + ld1--; + ld2--; + } + + /* Saving a full library name. */ + add_to_list (&libs, arg); + } +#endif } } - /* 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 (strncmp (p, "-shared", sizeof ("shared") - 1) == 0) - shared_obj = 1; - - if (*q) q++; - p = q; - } - #ifdef COLLECT_EXPORT_LIST + /* This is added only for debugging purposes. */ + if (debug) + { + fprintf (stderr, "List of libraries:\n"); + dump_list (stderr, "\t", libs.first); + } + /* 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; + char **export_object_lst = object_lst; + while (export_object_lst < object) + scan_prog_file (*export_object_lst++, PASS_OBJ); + } + { + struct id *list = libs.first; + for (; list; list = list->next) + scan_prog_file (list->name, PASS_FIRST); + } + { + char *buf1 = alloca (strlen (export_file) + 5); + char *buf2 = alloca (strlen (import_file) + 5); + sprintf (buf1, "-bE:%s", export_file); + sprintf (buf2, "-bI:%s", import_file); + *ld1++ = buf1; + *ld2++ = buf1; + *ld1++ = buf2; + *ld2++ = buf2; 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)) fatal_perror ("closing %s", export_file); + importf = fopen (import_file, "w"); + if (importf == (FILE *) 0) + fatal_perror ("%s", import_file); + write_import_file (importf); + if (fclose (importf)) + fatal_perror ("closing %s", import_file); } #endif *c_ptr++ = c_file; - *object = *c_ptr = *ld1 = (char *)0; + *object = *c_ptr = *ld1 = (char *) 0; if (vflag) { @@ -1371,10 +1387,6 @@ main (argc, argv) fprintf (stderr, "o_file = %s\n", (o_file ? o_file : "not found")); - ptr = getenv ("COLLECT_NAMES"); - if (ptr) - fprintf (stderr, "COLLECT_NAMES = %s\n", ptr); - ptr = getenv ("COLLECT_GCC_OPTIONS"); if (ptr) fprintf (stderr, "COLLECT_GCC_OPTIONS = %s\n", ptr); @@ -1394,23 +1406,42 @@ main (argc, argv) fprintf (stderr, "\n"); } - /* Load the program, searching all libraries. */ + /* Load the program, searching all libraries and attempting to provide + undefined symbols from repository information. */ - collect_execute ("ld", ld1_argv, ldout); - do_wait ("ld"); - dump_file (ldout); - unlink (ldout); + /* On AIX we do this later. */ +#ifndef COLLECT_EXPORT_LIST + do_tlink (ld1_argv, object_lst); +#endif - /* 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; + /* If -r or they will be run via some other method, do not build the + constructor or destructor list, just return now. */ + if (rflag +#ifndef COLLECT_EXPORT_LIST + || ! do_collecting +#endif + ) + { +#ifdef COLLECT_EXPORT_LIST + /* But make sure we delete the export file we may have created. */ + if (export_file != 0 && export_file[0]) + maybe_unlink (export_file); + if (import_file != 0 && import_file[0]) + maybe_unlink (import_file); +#endif + maybe_unlink (c_file); + maybe_unlink (o_file); + 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. */ + /* On AIX we already done scanning for global constructors/destructors. */ +#ifndef COLLECT_EXPORT_LIST scan_prog_file (output_file, PASS_FIRST); +#endif #ifdef SCAN_LIBRARIES scan_libraries (output_file); @@ -1423,14 +1454,19 @@ main (argc, argv) } if (constructors.number == 0 && destructors.number == 0 -#ifdef LDD_SUFFIX + && frame_tables.number == 0 +#if defined (SCAN_LIBRARIES) || defined (COLLECT_EXPORT_LIST) /* If we will be running these functions ourselves, we want to emit - stubs into the shared library so that we don't have to relink + stubs into the shared library so that we do not have to relink dependent programs when we add static objects. */ && ! shared_obj #endif ) { +#ifdef COLLECT_EXPORT_LIST + /* Doing tlink without additional code generation */ + do_tlink (ld1_argv, object_lst); +#endif /* Strip now if it was requested on the command line. */ if (strip_flag) { @@ -1443,13 +1479,16 @@ main (argc, argv) #ifdef COLLECT_EXPORT_LIST maybe_unlink (export_file); + maybe_unlink (import_file); #endif + maybe_unlink (c_file); + maybe_unlink (o_file); 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); @@ -1464,7 +1503,7 @@ main (argc, argv) *ld2++ = LD_FINI_SWITCH; *ld2++ = fininame; #endif - *ld2 = (char*)0; + *ld2 = (char*) 0; #ifdef COLLECT_EXPORT_LIST if (shared_obj) @@ -1474,7 +1513,7 @@ main (argc, argv) 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)) @@ -1496,23 +1535,34 @@ main (argc, argv) } /* 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); +#ifdef COLLECT_EXPORT_LIST + /* On AIX we must call tlink because of possible templates resolution */ + do_tlink (ld2_argv, object_lst); +#else + /* Otherwise, simply call ld because tlink is already done */ fork_execute ("ld", ld2_argv); /* Let scan_prog_file do any final mods (OSF/rose needs this for constructors/destructors in shared libraries. */ scan_prog_file (output_file, PASS_SECOND); +#endif maybe_unlink (c_file); maybe_unlink (o_file); + +#ifdef COLLECT_EXPORT_LIST maybe_unlink (export_file); + maybe_unlink (import_file); +#endif + return 0; } -/* 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) @@ -1539,7 +1589,7 @@ collect_wait (prog) (status & 0200) ? ", core dumped" : ""); #endif - collect_exit (127); + collect_exit (FATAL_EXIT_CODE); } if (WIFEXITED (status)) @@ -1581,7 +1631,7 @@ collect_execute (prog, argv, redir) 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"); @@ -1590,12 +1640,13 @@ collect_execute (prog, argv, redir) fflush (stdout); fflush (stderr); - /* If we can't find a program we need, complain error. Do this here - since we might not end up needing something that we couldn't find. */ + /* If we cannot find a program we need, complain error. Do this here + since we might not end up needing something that we could not find. */ if (argv[0] == 0) fatal ("cannot find `%s'", prog); +#ifndef __CYGWIN32__ pid = vfork (); if (pid == -1) { @@ -1612,14 +1663,19 @@ collect_execute (prog, argv, redir) { unlink (redir); if (freopen (redir, "a", stdout) == NULL) - fatal_perror ("redirecting stdout"); + fatal_perror ("redirecting stdout: %s", redir); if (freopen (redir, "a", stderr) == NULL) - fatal_perror ("redirecting stderr"); + fatal_perror ("redirecting stderr: %s", redir); } execvp (argv[0], argv); fatal_perror ("executing %s", prog); } +#else + pid = _spawnvp (_P_NOWAIT, argv[0], argv); + if (pid == -1) + fatal ("spawnvp failed"); +#endif } static void @@ -1694,6 +1750,53 @@ write_list (stream, prefix, list) } } +#ifdef COLLECT_EXPORT_LIST +/* This function is really used only on AIX, but may be useful. */ +static int +is_in_list (prefix, list) + char *prefix; + struct id *list; +{ + while (list) + { + if (!strcmp (prefix, list->name)) return 1; + list = list->next; + } + return 0; +} +#endif + +/* Added for debugging purpose. */ +#ifdef COLLECT_EXPORT_LIST +static void +dump_list (stream, prefix, list) + FILE *stream; + char *prefix; + struct id *list; +{ + while (list) + { + fprintf (stream, "%s%s,\n", prefix, list->name); + list = list->next; + } +} +#endif + +#if 0 +static void +dump_prefix_list (stream, prefix, list) + FILE *stream; + char *prefix; + struct prefix_list *list; +{ + while (list) + { + fprintf (stream, "%s%s,\n", prefix, list->prefix); + list = list->next; + } +} +#endif + static void write_list_with_asm (stream, prefix, list) FILE *stream; @@ -1717,6 +1820,7 @@ write_c_file_stat (stream, name) char *name; { char *prefix, *p, *q; + int frames = (frame_tables.number > 0); /* Figure out name of output_file, stripping off .so version. */ p = rindex (output_file, '/'); @@ -1749,7 +1853,7 @@ write_c_file_stat (stream, name) strncpy (prefix, p, q - p); prefix[q - p] = 0; for (q = prefix; *q; q++) - if (!isalnum (*q)) + if (!ISALNUM (*q)) *q = '_'; if (debug) fprintf (stderr, "\nwrite_c_file - output name is %s, prefix is %s\n", @@ -1770,15 +1874,49 @@ write_c_file_stat (stream, name) fprintf (stream, "static int count;\n"); fprintf (stream, "typedef void entry_pt();\n"); write_list_with_asm (stream, "extern entry_pt ", constructors.first); + + if (frames) + { + write_list_with_asm (stream, "extern void *", frame_tables.first); + + fprintf (stream, "\tstatic void *frame_table[] = {\n"); + write_list (stream, "\t\t&", frame_tables.first); + fprintf (stream, "\t0\n};\n"); + + /* This must match what's in frame.h. */ + fprintf (stream, "struct object {\n"); + fprintf (stream, " void *pc_begin;\n"); + fprintf (stream, " void *pc_end;\n"); + fprintf (stream, " void *fde_begin;\n"); + fprintf (stream, " void *fde_array;\n"); + fprintf (stream, " __SIZE_TYPE__ count;\n"); + fprintf (stream, " struct object *next;\n"); + fprintf (stream, "};\n"); + + fprintf (stream, "extern void __register_frame_info_table (void *, struct object *);\n"); + fprintf (stream, "extern void *__deregister_frame_info (void *);\n"); + + fprintf (stream, "static void reg_frame () {\n"); + fprintf (stream, "\tstatic struct object ob;\n"); + fprintf (stream, "\t__register_frame_info_table (frame_table, &ob);\n"); + fprintf (stream, "\t}\n"); + + fprintf (stream, "static void dereg_frame () {\n"); + fprintf (stream, "\t__deregister_frame_info (frame_table);\n"); + fprintf (stream, "\t}\n"); + } + fprintf (stream, "void %s() {\n", initname); - if (constructors.number > 0) + if (constructors.number > 0 || frames) { fprintf (stream, "\tstatic entry_pt *ctors[] = {\n"); write_list (stream, "\t\t", constructors.first); + if (frames) + fprintf (stream, "\treg_frame,\n"); fprintf (stream, "\t};\n"); fprintf (stream, "\tentry_pt **p;\n"); fprintf (stream, "\tif (count++ != 0) return;\n"); - fprintf (stream, "\tp = ctors + %d;\n", constructors.number); + fprintf (stream, "\tp = ctors + %d;\n", constructors.number + frames); fprintf (stream, "\twhile (p > ctors) (*--p)();\n"); } else @@ -1786,16 +1924,18 @@ write_c_file_stat (stream, name) fprintf (stream, "}\n"); write_list_with_asm (stream, "extern entry_pt ", destructors.first); fprintf (stream, "void %s() {\n", fininame); - if (destructors.number > 0) + if (destructors.number > 0 || frames) { fprintf (stream, "\tstatic entry_pt *dtors[] = {\n"); write_list (stream, "\t\t", destructors.first); + if (frames) + fprintf (stream, "\tdereg_frame,\n"); fprintf (stream, "\t};\n"); fprintf (stream, "\tentry_pt **p;\n"); fprintf (stream, "\tif (--count != 0) return;\n"); fprintf (stream, "\tp = dtors;\n"); fprintf (stream, "\twhile (p < dtors + %d) (*p++)();\n", - destructors.number); + destructors.number + frames); } fprintf (stream, "}\n"); @@ -1806,8 +1946,9 @@ write_c_file_stat (stream, name) } } -/* Write the constructor/destructor tables. */ +/* Write the constructor/destructor tables. */ +#ifndef LD_INIT_SWITCH static void write_c_file_glob (stream, name) FILE *stream; @@ -1815,39 +1956,80 @@ write_c_file_glob (stream, name) { /* Write the tables as C code */ + int frames = (frame_tables.number > 0); + fprintf (stream, "typedef void entry_pt();\n\n"); write_list_with_asm (stream, "extern entry_pt ", constructors.first); - + + if (frames) + { + write_list_with_asm (stream, "extern void *", frame_tables.first); + + fprintf (stream, "\tstatic void *frame_table[] = {\n"); + write_list (stream, "\t\t&", frame_tables.first); + fprintf (stream, "\t0\n};\n"); + + /* This must match what's in frame.h. */ + fprintf (stream, "struct object {\n"); + fprintf (stream, " void *pc_begin;\n"); + fprintf (stream, " void *pc_end;\n"); + fprintf (stream, " void *fde_begin;\n"); + fprintf (stream, " void *fde_array;\n"); + fprintf (stream, " __SIZE_TYPE__ count;\n"); + fprintf (stream, " struct object *next;\n"); + fprintf (stream, "};\n"); + + fprintf (stream, "extern void __register_frame_info_table (void *, struct object *);\n"); + fprintf (stream, "extern void *__deregister_frame_info (void *);\n"); + + fprintf (stream, "static void reg_frame () {\n"); + fprintf (stream, "\tstatic struct object ob;\n"); + fprintf (stream, "\t__register_frame_info_table (frame_table, &ob);\n"); + fprintf (stream, "\t}\n"); + + fprintf (stream, "static void dereg_frame () {\n"); + fprintf (stream, "\t__deregister_frame_info (frame_table);\n"); + fprintf (stream, "\t}\n"); + } + fprintf (stream, "\nentry_pt * __CTOR_LIST__[] = {\n"); - fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number); + fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number + frames); write_list (stream, "\t", constructors.first); + if (frames) + fprintf (stream, "\treg_frame,\n"); fprintf (stream, "\t0\n};\n\n"); 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); + fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number + frames); write_list (stream, "\t", destructors.first); + if (frames) + fprintf (stream, "\tdereg_frame,\n"); fprintf (stream, "\t0\n};\n\n"); fprintf (stream, "extern entry_pt %s;\n", NAME__MAIN); fprintf (stream, "entry_pt *__main_reference = %s;\n\n", NAME__MAIN); } +#endif /* ! LD_INIT_SWITCH */ static void write_c_file (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"); } +#ifdef COLLECT_EXPORT_LIST static void write_export_file (stream) FILE *stream; @@ -1856,6 +2038,17 @@ write_export_file (stream) for (; list; list = list->next) fprintf (stream, "%s\n", list->name); } + +static void +write_import_file (stream) + FILE *stream; +{ + struct id *list = imports.first; + fprintf (stream, "%s\n", "#! ."); + for (; list; list = list->next) + fprintf (stream, "%s\n", list->name); +} +#endif #ifdef OBJECT_FORMAT_NONE @@ -1885,7 +2078,7 @@ scan_prog_file (prog_name, which_pass) if (which_pass == PASS_SECOND) return; - /* If we don't have an `nm', complain. */ + /* If we do not have an `nm', complain. */ if (nm_file_name == 0) fatal ("cannot find `nm'"); @@ -1894,13 +2087,13 @@ scan_prog_file (prog_name, which_pass) 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. */ @@ -1909,7 +2102,7 @@ scan_prog_file (prog_name, which_pass) 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"); @@ -1958,13 +2151,13 @@ scan_prog_file (prog_name, which_pass) 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] == ' ') @@ -1975,8 +2168,8 @@ scan_prog_file (prog_name, which_pass) 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 != '|'; + Do not include `|', because Encore nm can tack that on the end. */ + for (end = p; (ch2 = *end) != '\0' && !ISSPACE (ch2) && ch2 != '|'; end++) continue; @@ -2010,6 +2203,10 @@ scan_prog_file (prog_name, which_pass) #endif break; + case 5: + if (which_pass != PASS_LIB) + add_to_list (&frame_tables, name); + default: /* not a constructor or destructor */ continue; } @@ -2043,7 +2240,7 @@ scan_prog_file (prog_name, which_pass) #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 */ @@ -2095,7 +2292,7 @@ libselect (d) 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. */ + invalid extensions must go last in the sort, so that they will not be used. */ static int libcompare (d1, d2) @@ -2106,7 +2303,7 @@ libcompare (d1, d2) char *e2 = (*d2)->d_name + i2; while (*e1 && *e2 && *e1 == '.' && *e2 == '.' - && e1[1] && isdigit (e1[1]) && e2[1] && isdigit (e2[1])) + && e1[1] && ISDIGIT (e1[1]) && e2[1] && ISDIGIT (e2[1])) { ++e1; ++e2; @@ -2119,7 +2316,7 @@ libcompare (d1, d2) if (*e1) { /* It has a valid numeric extension, prefer this one. */ - if (*e1 == '.' && e1[1] && isdigit (e1[1])) + if (*e1 == '.' && e1[1] && ISDIGIT (e1[1])) return 1; /* It has a invalid numeric extension, must prefer the other one. */ else @@ -2128,7 +2325,7 @@ libcompare (d1, d2) else if (*e2) { /* It has a valid numeric extension, prefer this one. */ - if (*e2 == '.' && e2[1] && isdigit (e2[1])) + if (*e2 == '.' && e2[1] && ISDIGIT (e2[1])) return -1; /* It has a invalid numeric extension, must prefer the other one. */ else @@ -2323,7 +2520,7 @@ scan_libraries (prog_name) char buf[1024]; FILE *inf; - /* If we don't have an `ldd', complain. */ + /* If we do not have an `ldd', complain. */ if (ldd_file_name == 0) { error ("cannot find `ldd'"); @@ -2401,7 +2598,7 @@ scan_libraries (prog_name) 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; @@ -2410,9 +2607,9 @@ scan_libraries (prog_name) 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 != '|'; + (ch2 = *end) != '\0' && ch2 != '\n' && !ISSPACE (ch2) && ch2 != '|'; end++) continue; *end = '\0'; @@ -2468,11 +2665,16 @@ scan_libraries (prog_name) # 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))) + ((X).n_scnum > N_UNDEF) && \ + (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) || \ + ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT))) +# define GCC_UNDEF_SYMBOL(X) \ + (((X).n_sclass == C_EXT) && ((X).n_scnum == N_UNDEF)) # define GCC_SYMINC(X) ((X).n_numaux+1) # define GCC_SYMZERO(X) 0 -# define GCC_CHECK_HDR(X) (1) +# define GCC_CHECK_HDR(X) \ + ((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \ + || (HEADER (X).f_magic == 0757 && aix64_flag)) #endif extern char *ldgetname (); @@ -2493,246 +2695,277 @@ scan_prog_file (prog_name, which_pass) { LDFILE *ldptr = NULL; int sym_index, sym_count; + int is_shared = 0; +#ifdef COLLECT_EXPORT_LIST + /* Should we generate an import list for given prog_name? */ + int import_flag = (which_pass == PASS_OBJ ? 0 : use_import_list (prog_name)); +#endif if (which_pass != PASS_FIRST && which_pass != PASS_OBJ) return; - 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); +#ifdef COLLECT_EXPORT_LIST + /* We do not need scanning for some standard C libraries. */ + if (which_pass == PASS_FIRST && ignore_library (prog_name)) + return; - if (GCC_CHECK_HDR (ldptr)) + /* On AIX we have a loop, because there is not much difference + between an object and an archive. This trick allows us to + eliminate scan_libraries() function. */ + do { - sym_count = GCC_SYMBOLS (ldptr); - sym_index = GCC_SYMZERO (ldptr); - while (sym_index < sym_count) +#endif + if ((ldptr = ldopen (prog_name, ldptr)) != NULL) { - GCC_SYMENT symbol; - - if (ldtbread (ldptr, sym_index, &symbol) <= 0) - break; - sym_index += GCC_SYMINC (symbol); + if (! MY_ISCOFF (HEADER (ldptr).f_magic)) + fatal ("%s: not a COFF file", prog_name); - if (GCC_OK_SYMBOL (symbol)) + if (GCC_CHECK_HDR (ldptr)) { - char *name; + sym_count = GCC_SYMBOLS (ldptr); + sym_index = GCC_SYMZERO (ldptr); - if ((name = ldgetname (ldptr, &symbol)) == NULL) - continue; /* should never happen */ +#ifdef COLLECT_EXPORT_LIST + /* Is current archive member a shared object? */ + is_shared = HEADER (ldptr).f_flags & F_SHROBJ; +#endif + + 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 XCOFF_DEBUGGING_INFO - /* All AIX function names have a duplicate entry beginning - with a dot. */ - if (*name == '.') - ++name; + /* 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; + switch (is_ctor_dtor (name)) + { + case 1: + if (! is_shared) add_to_list (&constructors, name); +#ifdef COLLECT_EXPORT_LIST + if (which_pass == PASS_OBJ) + add_to_list (&exports, name); + /* If this symbol was undefined and we are building + an import list, we should add a symbol to this + list. */ + else + if (import_flag + && is_in_list (name, undefined.first)) + add_to_list (&imports, name); +#endif + break; + + case 2: + if (! is_shared) add_to_list (&destructors, name); +#ifdef COLLECT_EXPORT_LIST + if (which_pass == PASS_OBJ) + add_to_list (&exports, name); + /* If this symbol was undefined and we are building + an import list, we should add a symbol to this + list. */ + else + if (import_flag + && is_in_list (name, undefined.first)) + add_to_list (&imports, name); +#endif + break; - case 2: - add_to_list (&destructors, name); - if (which_pass == PASS_OBJ) - add_to_list (&exports, name); - break; +#ifdef COLLECT_EXPORT_LIST + case 3: + if (is_shared) + add_to_list (&constructors, name); + break; - default: /* not a constructor or destructor */ - continue; - } + case 4: + if (is_shared) + add_to_list (&destructors, name); + break; +#endif + + default: /* not a constructor or destructor */ +#ifdef COLLECT_EXPORT_LIST + /* If we are building a shared object on AIX we need + to explicitly export all global symbols or add + them to import list. */ + if (shared_obj) + { + if (which_pass == PASS_OBJ && (! export_flag)) + add_to_list (&exports, name); + else if (! is_shared && which_pass == PASS_FIRST + && import_flag + && is_in_list(name, undefined.first)) + add_to_list (&imports, name); + } +#endif + 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); + 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); + if (debug) + fprintf (stderr, + "\tiss = %5d, value = %5ld, index = %5d, name = %s\n", + symbol.iss, (long) symbol.value, symbol.index, name); +#endif + } +#ifdef COLLECT_EXPORT_LIST + /* If we are building a shared object we should collect + information about undefined symbols for later + import list generation. */ + else if (shared_obj && GCC_UNDEF_SYMBOL (symbol)) + { + char *name; + + if ((name = ldgetname (ldptr, &symbol)) == NULL) + continue; /* should never happen */ + + /* All AIX function names have a duplicate entry + beginning with a dot. */ + if (*name == '.') + ++name; + add_to_list (&undefined, name); + } #endif + } + } +#ifdef COLLECT_EXPORT_LIST + else + { + /* If archive contains both 32-bit and 64-bit objects, + we want to skip objects in other mode so mismatch normal. */ + if (debug) + fprintf (stderr, "%s : magic=%o aix64=%d mismatch\n", + prog_name, HEADER (ldptr).f_magic, aix64_flag); } +#endif + } + else + { + fatal ("%s: cannot open as COFF file", prog_name); } +#ifdef COLLECT_EXPORT_LIST + /* On AIX loop continues while there are more members in archive. */ } - + while (ldclose (ldptr) == FAILURE); +#else + /* Otherwise we simply close ldptr. */ (void) ldclose(ldptr); +#endif } -#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) +#ifdef COLLECT_EXPORT_LIST + +/* This new function is used to decide whether we should + generate import list for an object or to use it directly. */ +static int +use_import_list (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); + char *p; - if (debug) - fprintf (stderr, "LIBPATH=%s\n", impbuf); - prefix_from_string (impbuf, &libpath); + /* If we do not build a shared object then import list should not be used. */ + if (! shared_obj) return 0; - /* 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; - } - } + /* Currently we check only for libgcc, but this can be changed in future. */ + p = strstr (prog_name, "libgcc.a"); + if (p != 0 && (strlen (p) == sizeof ("libgcc.a") - 1)) + return 1; + return 0; +} - 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); +/* Given a library name without "lib" prefix, this function + returns a full library name including a path. */ +static char * +resolve_lib_name (name) + char *name; +{ + char *lib_buf; + int i, j, l = 0; + + for (i = 0; libpaths[i]; i++) + if (libpaths[i]->max_len > l) + l = libpaths[i]->max_len; + + lib_buf = xmalloc (l + strlen(name) + 10); - do + for (i = 0; libpaths[i]; i++) + { + struct prefix_list *list = libpaths[i]->plist; + for (; list; list = list->next) + { + for (j = 0; libexts[j]; j++) { - /* 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) + /* The following lines are needed because path_prefix list + may contain directories both with trailing '/' and + without it. */ + char *p = ""; + if (list->prefix[strlen(list->prefix)-1] != '/') + p = "/"; + sprintf (lib_buf, "%s%slib%s.%s", + list->prefix, p, name, libexts[j]); +if (debug) fprintf (stderr, "searching for: %s\n", lib_buf); + if (file_exists (lib_buf)) { - 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; - } - } - } +if (debug) fprintf (stderr, "found: %s\n", lib_buf); + return (lib_buf); } - 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); */ } } + if (debug) + fprintf (stderr, "not found\n"); + else + fatal ("Library lib%s not found", name); + return (NULL); +} + +/* Array of standard AIX libraries which should not + be scanned for ctors/dtors. */ +static char* aix_std_libs[] = { + "/unix", + "/lib/libc.a", + "/lib/libc_r.a", + "/usr/lib/libc.a", + "/usr/lib/libc_r.a", + "/usr/lib/threads/libc.a", + "/usr/ccs/lib/libc.a", + "/usr/ccs/lib/libc_r.a", + NULL +}; + +/* This function checks the filename and returns 1 + if this name matches the location of a standard AIX library. */ +static int +ignore_library (name) + char *name; +{ + char **p = &aix_std_libs[0]; + while (*p++ != NULL) + if (! strcmp (name, *p)) return 1; + return 0; } -#endif /* XCOFF_SCAN_LIBS */ + +#endif #endif /* OBJECT_FORMAT_COFF */ @@ -2787,7 +3020,7 @@ extern int encode_mach_o_hdr (); 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 *)); @@ -2826,7 +3059,7 @@ scan_prog_file (prog_name, which_pass) prog_fd = open (prog_name, (rw) ? O_RDWR : O_RDONLY); if (prog_fd < 0) - fatal_perror ("can't read %s", prog_name); + fatal_perror ("cannot read %s", prog_name); obj_file = read_file (prog_name, prog_fd, rw); obj = obj_file->start; @@ -2930,10 +3163,10 @@ scan_prog_file (prog_name, which_pass) 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; @@ -2998,11 +3231,11 @@ scan_prog_file (prog_name, which_pass) fatal ("no cmd_strings found"); /* Add __main to initializer list. - If we are building a program instead of a shared library, don't + If we are building a program instead of a shared library, do not 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); @@ -3057,7 +3290,7 @@ scan_prog_file (prog_name, which_pass) 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; } } @@ -3096,7 +3329,7 @@ add_func_table (hdr_p, load_array, sym, type) 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; @@ -3205,7 +3438,7 @@ print_load_command (load_hdr, offset, number) int number; { mo_long_t type = load_hdr->hdr.ldci_cmd_type; - char *type_str = (char *)0; + char *type_str = (char *) 0; switch (type) { @@ -3230,7 +3463,7 @@ print_load_command (load_hdr, offset, number) (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) @@ -3269,7 +3502,7 @@ static void bad_header (status) int status; { - char *msg = (char *)0; + char *msg = (char *) 0; switch (status) { @@ -3281,7 +3514,7 @@ bad_header (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); @@ -3319,14 +3552,14 @@ read_file (name, fd, rw) 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 |