| Index: gcc/gcc/collect2.c
|
| diff --git a/gcc/gcc/collect2.c b/gcc/gcc/collect2.c
|
| index 3f62dfe40b3abd5b3186cfb813b2afa7731507fe..f5498aa5e469630bb9d4e07fce70cbb85b3e2edc 100644
|
| --- a/gcc/gcc/collect2.c
|
| +++ b/gcc/gcc/collect2.c
|
| @@ -1,7 +1,7 @@
|
| /* Collect static initialization info into data structures that can be
|
| traversed by C++ initialization and finalization routines.
|
| Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
|
| - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
|
| + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
|
| Free Software Foundation, Inc.
|
| Contributed by Chris Smith (csmith@convex.com).
|
| Heavily modified by Michael Meissner (meissner@cygnus.com),
|
| @@ -35,6 +35,10 @@ along with GCC; see the file COPYING3. If not see
|
| # define SIGCHLD SIGCLD
|
| #endif
|
|
|
| +/* TARGET_64BIT may be defined to use driver specific functionality. */
|
| +#undef TARGET_64BIT
|
| +#define TARGET_64BIT TARGET_64BIT_DEFAULT
|
| +
|
| #ifndef LIBRARY_PATH_ENV
|
| #define LIBRARY_PATH_ENV "LIBRARY_PATH"
|
| #endif
|
| @@ -42,6 +46,7 @@ along with GCC; see the file COPYING3. If not see
|
| #define COLLECT
|
|
|
| #include "collect2.h"
|
| +#include "collect2-aix.h"
|
| #include "demangle.h"
|
| #include "obstack.h"
|
| #include "intl.h"
|
| @@ -54,7 +59,9 @@ along with GCC; see the file COPYING3. If not see
|
| cross-versions are in the proper directories. */
|
|
|
| #ifdef CROSS_DIRECTORY_STRUCTURE
|
| +#ifndef CROSS_AIX_SUPPORT
|
| #undef OBJECT_FORMAT_COFF
|
| +#endif
|
| #undef MD_EXEC_PREFIX
|
| #undef REAL_LD_FILE_NAME
|
| #undef REAL_NM_FILE_NAME
|
| @@ -72,6 +79,7 @@ along with GCC; see the file COPYING3. If not see
|
|
|
| #ifdef OBJECT_FORMAT_COFF
|
|
|
| +#ifndef CROSS_DIRECTORY_STRUCTURE
|
| #include <a.out.h>
|
| #include <ar.h>
|
|
|
| @@ -86,6 +94,7 @@ along with GCC; see the file COPYING3. If not see
|
| #endif
|
|
|
| #include <ldfcn.h>
|
| +#endif
|
|
|
| /* Some systems have an ISCOFF macro, but others do not. In some cases
|
| the macro may be wrong. MY_ISCOFF is defined in tm.h files for machines
|
| @@ -140,6 +149,15 @@ int do_collecting = 1;
|
| int do_collecting = 0;
|
| #endif
|
|
|
| +/* Cook up an always defined indication of whether we proceed the
|
| + "EXPORT_LIST" way. */
|
| +
|
| +#ifdef COLLECT_EXPORT_LIST
|
| +#define DO_COLLECT_EXPORT_LIST 1
|
| +#else
|
| +#define DO_COLLECT_EXPORT_LIST 0
|
| +#endif
|
| +
|
| /* Nonzero if we should suppress the automatic demangling of identifiers
|
| in linker error messages. Set from COLLECT_NO_DEMANGLE. */
|
| int no_demangle;
|
| @@ -160,15 +178,6 @@ struct head
|
| int number;
|
| };
|
|
|
| -/* Enumeration giving which pass this is for scanning the program file. */
|
| -
|
| -enum pass {
|
| - PASS_FIRST, /* without constructors */
|
| - PASS_OBJ, /* individual objects */
|
| - PASS_LIB, /* looking for shared libraries */
|
| - PASS_SECOND /* with constructors linked in */
|
| -};
|
| -
|
| int vflag; /* true if -v */
|
| static int rflag; /* true if -r */
|
| static int strip_flag; /* true if -s */
|
| @@ -179,6 +188,15 @@ static int aix64_flag; /* true if -b64 */
|
| static int aixrtl_flag; /* true if -brtl */
|
| #endif
|
|
|
| +enum lto_mode_d {
|
| + LTO_MODE_NONE, /* Not doing LTO. */
|
| + LTO_MODE_LTO, /* Normal LTO. */
|
| + LTO_MODE_WHOPR /* WHOPR. */
|
| +};
|
| +
|
| +/* Current LTO mode. */
|
| +static enum lto_mode_d lto_mode = LTO_MODE_NONE;
|
| +
|
| int debug; /* true if -debug */
|
|
|
| static int shared_obj; /* true if -shared */
|
| @@ -188,6 +206,7 @@ static const char *o_file; /* <xxx>.o for constructor/destructor list. */
|
| #ifdef COLLECT_EXPORT_LIST
|
| static const char *export_file; /* <xxx>.x for AIX export list. */
|
| #endif
|
| +static char **lto_o_files; /* Output files for LTO. */
|
| const char *ldout; /* File for ld stdout. */
|
| const char *lderrout; /* File for ld stderr. */
|
| static const char *output_file; /* Output file for ld. */
|
| @@ -212,6 +231,14 @@ static char *response_file; /* Name of any current response file */
|
| struct obstack temporary_obstack;
|
| char * temporary_firstobj;
|
|
|
| +/* A string that must be prepended to a target OS path in order to find
|
| + it on the host system. */
|
| +#ifdef TARGET_SYSTEM_ROOT
|
| +static const char *target_system_root = TARGET_SYSTEM_ROOT;
|
| +#else
|
| +static const char *target_system_root = "";
|
| +#endif
|
| +
|
| /* Structure to hold all the directories in which to search for files to
|
| execute. */
|
|
|
| @@ -237,6 +264,25 @@ static struct path_prefix *libpaths[3] = {&cmdline_lib_dirs,
|
| &libpath_lib_dirs, NULL};
|
| #endif
|
|
|
| +/* List of names of object files containing LTO information.
|
| + These are a subset of the object file names appearing on the
|
| + command line, and must be identical, in the sense of pointer
|
| + equality, with the names passed to maybe_run_lto_and_relink(). */
|
| +
|
| +struct lto_object
|
| +{
|
| + const char *name; /* Name of object file. */
|
| + struct lto_object *next; /* Next in linked list. */
|
| +};
|
| +
|
| +struct lto_object_list
|
| +{
|
| + struct lto_object *first; /* First list element. */
|
| + struct lto_object *last; /* Last list element. */
|
| +};
|
| +
|
| +static struct lto_object_list lto_objects;
|
| +
|
| /* Special kinds of symbols that a name may denote. */
|
|
|
| typedef enum {
|
| @@ -259,6 +305,7 @@ static void prefix_from_string (const char *, struct path_prefix *);
|
| static void do_wait (const char *, struct pex_obj *);
|
| static void fork_execute (const char *, char **);
|
| static void maybe_unlink (const char *);
|
| +static void maybe_unlink_list (char **);
|
| static void add_to_list (struct head *, const char *);
|
| static int extract_init_priority (const char *);
|
| static void sort_ids (struct head *);
|
| @@ -275,7 +322,6 @@ static void write_c_file_stat (FILE *, const char *);
|
| #ifndef LD_INIT_SWITCH
|
| static void write_c_file_glob (FILE *, const char *);
|
| #endif
|
| -static void scan_prog_file (const char *, enum pass);
|
| #ifdef SCAN_LIBRARIES
|
| static void scan_libraries (const char *);
|
| #endif
|
| @@ -290,6 +336,51 @@ static void write_aix_file (FILE *, struct id *);
|
| static char *resolve_lib_name (const char *);
|
| #endif
|
| static char *extract_string (const char **);
|
| +
|
| +/* Enumerations describing which pass this is for scanning the
|
| + program file ... */
|
| +
|
| +typedef enum {
|
| + PASS_FIRST, /* without constructors */
|
| + PASS_OBJ, /* individual objects */
|
| + PASS_LIB, /* looking for shared libraries */
|
| + PASS_SECOND, /* with constructors linked in */
|
| + PASS_LTOINFO /* looking for objects with LTO info */
|
| +} scanpass;
|
| +
|
| +/* ... and which kinds of symbols are to be considered. */
|
| +
|
| +enum scanfilter_masks {
|
| + SCAN_NOTHING = 0,
|
| +
|
| + SCAN_CTOR = 1 << SYM_CTOR,
|
| + SCAN_DTOR = 1 << SYM_DTOR,
|
| + SCAN_INIT = 1 << SYM_INIT,
|
| + SCAN_FINI = 1 << SYM_FINI,
|
| + SCAN_DWEH = 1 << SYM_DWEH,
|
| + SCAN_ALL = ~0
|
| +};
|
| +
|
| +/* This type is used for parameters and variables which hold
|
| + combinations of the flags in enum scanfilter_masks. */
|
| +typedef int scanfilter;
|
| +
|
| +/* Scan the name list of the loaded program for the symbols g++ uses for
|
| + static constructors and destructors.
|
| +
|
| + The SCANPASS argument tells which collect processing pass this is for and
|
| + the SCANFILTER argument tells which kinds of symbols to consider in this
|
| + pass. Symbols of a special kind not in the filter mask are considered as
|
| + regular ones.
|
| +
|
| + The constructor table begins at __CTOR_LIST__ and contains a count of the
|
| + number of pointers (or -1 if the constructors are built in a separate
|
| + section by the linker), followed by the pointers to the constructor
|
| + functions, terminated with a null pointer. The destructor table has the
|
| + same format, and begins at __DTOR_LIST__. */
|
| +
|
| +static void scan_prog_file (const char *, scanpass, scanfilter);
|
| +
|
|
|
| /* Delete tempfiles and exit function. */
|
|
|
| @@ -307,6 +398,9 @@ collect_exit (int status)
|
| maybe_unlink (export_file);
|
| #endif
|
|
|
| + if (lto_o_files)
|
| + maybe_unlink_list (lto_o_files);
|
| +
|
| if (ldout != 0 && ldout[0])
|
| {
|
| dump_file (ldout, stdout);
|
| @@ -340,6 +434,17 @@ notice (const char *cmsgid, ...)
|
| va_end (ap);
|
| }
|
|
|
| +/* Notify user of a non-error, without translating the format string. */
|
| +void
|
| +notice_translated (const char *cmsgid, ...)
|
| +{
|
| + va_list ap;
|
| +
|
| + va_start (ap, cmsgid);
|
| + vfprintf (stderr, cmsgid, ap);
|
| + va_end (ap);
|
| +}
|
| +
|
| /* Die when sys call fails. */
|
|
|
| void
|
| @@ -416,6 +521,9 @@ handler (int signo)
|
| maybe_unlink (export_file);
|
| #endif
|
|
|
| + if (lto_o_files)
|
| + maybe_unlink_list (lto_o_files);
|
| +
|
| if (response_file)
|
| maybe_unlink (response_file);
|
|
|
| @@ -538,7 +646,7 @@ dump_file (const char *name, FILE *to)
|
| static symkind
|
| is_ctor_dtor (const char *s)
|
| {
|
| - struct names { const char *const name; const int len; const int ret;
|
| + struct names { const char *const name; const int len; symkind ret;
|
| const int two_underscores; };
|
|
|
| const struct names *p;
|
| @@ -759,6 +867,247 @@ prefix_from_string (const char *p, struct path_prefix *pprefix)
|
| }
|
| free (nstore);
|
| }
|
| +
|
| +#ifdef OBJECT_FORMAT_NONE
|
| +
|
| +/* Add an entry for the object file NAME to object file list LIST.
|
| + New entries are added at the end of the list. The original pointer
|
| + value of NAME is preserved, i.e., no string copy is performed. */
|
| +
|
| +static void
|
| +add_lto_object (struct lto_object_list *list, const char *name)
|
| +{
|
| + struct lto_object *n = XNEW (struct lto_object);
|
| + n->name = name;
|
| + n->next = NULL;
|
| +
|
| + if (list->last)
|
| + list->last->next = n;
|
| + else
|
| + list->first = n;
|
| +
|
| + list->last = n;
|
| +}
|
| +#endif /* OBJECT_FORMAT_NONE */
|
| +
|
| +
|
| +/* Perform a link-time recompilation and relink if any of the object
|
| + files contain LTO info. The linker command line LTO_LD_ARGV
|
| + represents the linker command that would produce a final executable
|
| + without the use of LTO. OBJECT_LST is a vector of object file names
|
| + appearing in LTO_LD_ARGV that are to be considerd for link-time
|
| + recompilation, where OBJECT is a pointer to the last valid element.
|
| + (This awkward convention avoids an impedance mismatch with the
|
| + usage of similarly-named variables in main().) The elements of
|
| + OBJECT_LST must be identical, i.e., pointer equal, to the
|
| + corresponding arguments in LTO_LD_ARGV.
|
| +
|
| + Upon entry, at least one linker run has been performed without the
|
| + use of any LTO info that might be present. Any recompilations
|
| + necessary for template instantiations have been performed, and
|
| + initializer/finalizer tables have been created if needed and
|
| + included in the linker command line LTO_LD_ARGV. If any of the
|
| + object files contain LTO info, we run the LTO back end on all such
|
| + files, and perform the final link with the LTO back end output
|
| + substituted for the LTO-optimized files. In some cases, a final
|
| + link with all link-time generated code has already been performed,
|
| + so there is no need to relink if no LTO info is found. In other
|
| + cases, our caller has not produced the final executable, and is
|
| + relying on us to perform the required link whether LTO info is
|
| + present or not. In that case, the FORCE argument should be true.
|
| + Note that the linker command line argument LTO_LD_ARGV passed into
|
| + this function may be modified in place. */
|
| +
|
| +static void
|
| +maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst,
|
| + const char **object, bool force)
|
| +{
|
| + const char **object_file = CONST_CAST2 (const char **, char **, object_lst);
|
| +
|
| + int num_lto_c_args = 1; /* Allow space for the terminating NULL. */
|
| +
|
| + while (object_file < object)
|
| + {
|
| + /* If file contains LTO info, add it to the list of LTO objects. */
|
| + scan_prog_file (*object_file++, PASS_LTOINFO, SCAN_ALL);
|
| +
|
| + /* Increment the argument count by the number of object file arguments
|
| + we will add. An upper bound suffices, so just count all of the
|
| + object files regardless of whether they contain LTO info. */
|
| + num_lto_c_args++;
|
| + }
|
| +
|
| + if (lto_objects.first)
|
| + {
|
| + const char *opts;
|
| + char **lto_c_argv;
|
| + const char **lto_c_ptr;
|
| + const char *cp;
|
| + const char **p, **q, **r;
|
| + const char **lto_o_ptr;
|
| + struct lto_object *list;
|
| + char *lto_wrapper = getenv ("COLLECT_LTO_WRAPPER");
|
| + struct pex_obj *pex;
|
| + const char *prog = "lto-wrapper";
|
| +
|
| + if (!lto_wrapper)
|
| + fatal ("COLLECT_LTO_WRAPPER must be set.");
|
| +
|
| + /* There is at least one object file containing LTO info,
|
| + so we need to run the LTO back end and relink. */
|
| +
|
| + /* Get compiler options passed down from the parent `gcc' command.
|
| + These must be passed to the LTO back end. */
|
| + opts = getenv ("COLLECT_GCC_OPTIONS");
|
| +
|
| + /* Increment the argument count by the number of inherited options.
|
| + Some arguments may be filtered out later. Again, an upper bound
|
| + suffices. */
|
| +
|
| + cp = opts;
|
| +
|
| + while (cp && *cp)
|
| + {
|
| + extract_string (&cp);
|
| + num_lto_c_args++;
|
| + }
|
| + obstack_free (&temporary_obstack, temporary_firstobj);
|
| +
|
| + if (debug)
|
| + num_lto_c_args++;
|
| +
|
| + /* Increment the argument count by the number of initial
|
| + arguments added below. */
|
| + num_lto_c_args += 9;
|
| +
|
| + lto_c_argv = (char **) xcalloc (sizeof (char *), num_lto_c_args);
|
| + lto_c_ptr = CONST_CAST2 (const char **, char **, lto_c_argv);
|
| +
|
| + *lto_c_ptr++ = lto_wrapper;
|
| + *lto_c_ptr++ = c_file_name;
|
| +
|
| + cp = opts;
|
| +
|
| + while (cp && *cp)
|
| + {
|
| + const char *s = extract_string (&cp);
|
| +
|
| + /* Pass the option or argument to the wrapper. */
|
| + *lto_c_ptr++ = xstrdup (s);
|
| + }
|
| + obstack_free (&temporary_obstack, temporary_firstobj);
|
| +
|
| + if (debug)
|
| + *lto_c_ptr++ = xstrdup ("-debug");
|
| +
|
| + /* Add LTO objects to the wrapper command line. */
|
| + for (list = lto_objects.first; list; list = list->next)
|
| + *lto_c_ptr++ = list->name;
|
| +
|
| + *lto_c_ptr = NULL;
|
| +
|
| + /* Save intermediate WPA files in lto1 if debug. */
|
| + if (debug)
|
| + putenv (xstrdup ("WPA_SAVE_LTRANS=1"));
|
| +
|
| + /* Run the LTO back end. */
|
| + pex = collect_execute (prog, lto_c_argv, NULL, NULL, PEX_SEARCH);
|
| + {
|
| + int c;
|
| + FILE *stream;
|
| + size_t i, num_files;
|
| + char *start, *end;
|
| +
|
| + stream = pex_read_output (pex, 0);
|
| + gcc_assert (stream);
|
| +
|
| + num_files = 0;
|
| + while ((c = getc (stream)) != EOF)
|
| + {
|
| + obstack_1grow (&temporary_obstack, c);
|
| + if (c == '\n')
|
| + ++num_files;
|
| + }
|
| +
|
| + lto_o_files = XNEWVEC (char *, num_files + 1);
|
| + lto_o_files[num_files] = NULL;
|
| + start = XOBFINISH (&temporary_obstack, char *);
|
| + for (i = 0; i < num_files; ++i)
|
| + {
|
| + end = start;
|
| + while (*end != '\n')
|
| + ++end;
|
| + *end = '\0';
|
| +
|
| + lto_o_files[i] = xstrdup (start);
|
| +
|
| + start = end + 1;
|
| + }
|
| +
|
| + obstack_free (&temporary_obstack, temporary_firstobj);
|
| + }
|
| + do_wait (prog, pex);
|
| + pex = NULL;
|
| +
|
| + /* After running the LTO back end, we will relink, substituting
|
| + the LTO output for the object files that we submitted to the
|
| + LTO. Here, we modify the linker command line for the relink. */
|
| + p = CONST_CAST2 (const char **, char **, lto_ld_argv);
|
| + lto_o_ptr = CONST_CAST2 (const char **, char **, lto_o_files);
|
| +
|
| + while (*p != NULL)
|
| + {
|
| + for (list = lto_objects.first; list; list = list->next)
|
| + {
|
| + if (*p == list->name) /* Note test for pointer equality! */
|
| + {
|
| + /* Excise argument from linker command line. */
|
| + if (*lto_o_ptr)
|
| + {
|
| + /* Replace first argument with LTO output file. */
|
| + *p++ = *lto_o_ptr++;
|
| + }
|
| + else
|
| + {
|
| + /* Move following arguments one position earlier,
|
| + overwriting the current argument. */
|
| + q = p;
|
| + r = p + 1;
|
| + while (*r != NULL)
|
| + *q++ = *r++;
|
| + *q = NULL;
|
| + }
|
| +
|
| + /* No need to continue searching the LTO object list. */
|
| + break;
|
| + }
|
| + }
|
| +
|
| + /* If we didn't find a match, move on to the next argument.
|
| + Otherwise, P has been set to the correct argument position
|
| + at which to continue. */
|
| + if (!list) ++p;
|
| + }
|
| +
|
| + /* The code above assumes we will never have more lto output files than
|
| + input files. Otherwise, we need to resize lto_ld_argv. Check this
|
| + assumption. */
|
| + if (*lto_o_ptr)
|
| + fatal ("too many lto output files");
|
| +
|
| + /* Run the linker again, this time replacing the object files
|
| + optimized by the LTO with the temporary file generated by the LTO. */
|
| + fork_execute ("ld", lto_ld_argv);
|
| +
|
| + maybe_unlink_list (lto_o_files);
|
| + }
|
| + else if (force)
|
| + {
|
| + /* Our caller is relying on us to do the link
|
| + even though there is no LTO back end work to be done. */
|
| + fork_execute ("ld", lto_ld_argv);
|
| + }
|
| +}
|
|
|
| /* Main program. */
|
|
|
| @@ -766,6 +1115,7 @@ int
|
| main (int argc, char **argv)
|
| {
|
| static const char *const ld_suffix = "ld";
|
| + static const char *const plugin_ld_suffix = PLUGIN_LD;
|
| static const char *const real_ld_suffix = "real-ld";
|
| static const char *const collect_ld_suffix = "collect-ld";
|
| static const char *const nm_suffix = "nm";
|
| @@ -784,6 +1134,8 @@ main (int argc, char **argv)
|
|
|
| const char *const full_ld_suffix =
|
| concat(target_machine, "-", ld_suffix, NULL);
|
| + const char *const full_plugin_ld_suffix =
|
| + concat(target_machine, "-", plugin_ld_suffix, NULL);
|
| const char *const full_nm_suffix =
|
| concat (target_machine, "-", nm_suffix, NULL);
|
| const char *const full_gnm_suffix =
|
| @@ -798,6 +1150,7 @@ main (int argc, char **argv)
|
| concat (target_machine, "-", gstrip_suffix, NULL);
|
| #else
|
| const char *const full_ld_suffix = ld_suffix;
|
| + const char *const full_plugin_ld_suffix = plugin_ld_suffix;
|
| const char *const full_nm_suffix = nm_suffix;
|
| const char *const full_gnm_suffix = gnm_suffix;
|
| #ifdef LDD_SUFFIX
|
| @@ -818,6 +1171,16 @@ main (int argc, char **argv)
|
| const char **c_ptr;
|
| char **ld1_argv;
|
| const char **ld1;
|
| + bool use_plugin = false;
|
| +
|
| + /* The kinds of symbols we will have to consider when scanning the
|
| + outcome of a first pass link. This is ALL to start with, then might
|
| + be adjusted before getting to the first pass link per se, typically on
|
| + AIX where we perform an early scan of objects and libraries to fetch
|
| + the list of global ctors/dtors and make sure they are not garbage
|
| + collected. */
|
| + scanfilter ld1_filter = SCAN_ALL;
|
| +
|
| char **ld2_argv;
|
| const char **ld2;
|
| char **object_lst;
|
| @@ -826,6 +1189,8 @@ main (int argc, char **argv)
|
| int num_c_args;
|
| char **old_argv;
|
|
|
| + bool use_verbose = false;
|
| +
|
| old_argv = argv;
|
| expandargv (&argc, &argv);
|
| if (argv != old_argv)
|
| @@ -857,9 +1222,12 @@ main (int argc, char **argv)
|
| /* Do not invoke xcalloc before this point, since locale needs to be
|
| set first, in case a diagnostic is issued. */
|
|
|
| - ld1 = (const char **)(ld1_argv = XCNEWVEC (char *, argc+4));
|
| - ld2 = (const char **)(ld2_argv = XCNEWVEC (char *, argc+11));
|
| - object = (const char **)(object_lst = XCNEWVEC (char *, argc));
|
| + ld1_argv = XCNEWVEC (char *, argc + 4);
|
| + ld1 = CONST_CAST2 (const char **, char **, ld1_argv);
|
| + ld2_argv = XCNEWVEC (char *, argc + 11);
|
| + ld2 = CONST_CAST2 (const char **, char **, ld2_argv);
|
| + object_lst = XCNEWVEC (char *, argc);
|
| + object = CONST_CAST2 (const char **, char **, object_lst);
|
|
|
| #ifdef DEBUG
|
| debug = 1;
|
| @@ -867,7 +1235,8 @@ main (int argc, char **argv)
|
|
|
| /* Parse command line early for instances of -debug. This allows
|
| the debug flag to be set before functions like find_a_file()
|
| - are called. */
|
| + are called. We also look for the -flto or -fwhopr flag to know
|
| + what LTO mode we are in. */
|
| {
|
| int i;
|
|
|
| @@ -875,6 +1244,38 @@ main (int argc, char **argv)
|
| {
|
| if (! strcmp (argv[i], "-debug"))
|
| debug = 1;
|
| + else if (! strcmp (argv[i], "-flto") && ! use_plugin)
|
| + {
|
| + use_verbose = true;
|
| + lto_mode = LTO_MODE_LTO;
|
| + }
|
| + else if (! strcmp (argv[i], "-fwhopr") && ! use_plugin)
|
| + {
|
| + use_verbose = true;
|
| + lto_mode = LTO_MODE_WHOPR;
|
| + }
|
| + else if (! strcmp (argv[i], "-plugin"))
|
| + {
|
| + use_plugin = true;
|
| + use_verbose = true;
|
| + lto_mode = LTO_MODE_NONE;
|
| + }
|
| +#ifdef COLLECT_EXPORT_LIST
|
| + /* since -brtl, -bexport, -b64 are not position dependent
|
| + also check for them here */
|
| + if ((argv[i][0] == '-') && (argv[i][1] == 'b'))
|
| + {
|
| + arg = argv[i];
|
| + /* We want to disable automatic exports on AIX when user
|
| + explicitly puts an export list in command line */
|
| + if (arg[2] == 'E' || strncmp (&arg[2], "export", 6) == 0)
|
| + export_flag = 1;
|
| + else if (arg[2] == '6' && arg[3] == '4')
|
| + aix64_flag = 1;
|
| + else if (arg[2] == 'r' && arg[3] == 't' && arg[4] == 'l')
|
| + aixrtl_flag = 1;
|
| + }
|
| +#endif
|
| }
|
| vflag = debug;
|
| }
|
| @@ -901,10 +1302,11 @@ main (int argc, char **argv)
|
| obstack_free (&temporary_obstack, temporary_firstobj);
|
|
|
| /* -fno-profile-arcs -fno-test-coverage -fno-branch-probabilities
|
| - -fno-exceptions -w */
|
| - num_c_args += 5;
|
| + -fno-exceptions -w -fno-whole-program */
|
| + num_c_args += 6;
|
|
|
| - c_ptr = (const char **) (c_argv = XCNEWVEC (char *, num_c_args));
|
| + c_argv = XCNEWVEC (char *, num_c_args);
|
| + c_ptr = CONST_CAST2 (const char **, char **, c_argv);
|
|
|
| if (argc < 2)
|
| fatal ("no arguments");
|
| @@ -955,11 +1357,17 @@ main (int argc, char **argv)
|
| /* Search the compiler directories for `ld'. We have protection against
|
| recursive calls in find_a_file. */
|
| if (ld_file_name == 0)
|
| - ld_file_name = find_a_file (&cpath, ld_suffix);
|
| + ld_file_name = find_a_file (&cpath,
|
| + use_plugin
|
| + ? plugin_ld_suffix
|
| + : ld_suffix);
|
| /* Search the ordinary system bin directories
|
| for `ld' (if native linking) or `TARGET-ld' (if cross). */
|
| if (ld_file_name == 0)
|
| - ld_file_name = find_a_file (&path, full_ld_suffix);
|
| + ld_file_name = find_a_file (&path,
|
| + use_plugin
|
| + ? full_plugin_ld_suffix
|
| + : full_ld_suffix);
|
|
|
| #ifdef REAL_NM_FILE_NAME
|
| nm_file_name = find_a_file (&path, REAL_NM_FILE_NAME);
|
| @@ -1062,6 +1470,11 @@ main (int argc, char **argv)
|
| *c_ptr++ = xstrdup (q);
|
| }
|
| }
|
| + if (use_verbose && *q == '-' && q[1] == 'v' && q[2] == 0)
|
| + {
|
| + /* Turn on trace in collect2 if needed. */
|
| + vflag = 1;
|
| + }
|
| }
|
| obstack_free (&temporary_obstack, temporary_firstobj);
|
| *c_ptr++ = "-fno-profile-arcs";
|
| @@ -1069,6 +1482,7 @@ main (int argc, char **argv)
|
| *c_ptr++ = "-fno-branch-probabilities";
|
| *c_ptr++ = "-fno-exceptions";
|
| *c_ptr++ = "-w";
|
| + *c_ptr++ = "-fno-whole-program";
|
|
|
| /* !!! When GCC calls collect2,
|
| it does not know whether it is calling collect2 or ld.
|
| @@ -1095,19 +1509,6 @@ main (int argc, char **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;
|
| - else if (arg[2] == '6' && arg[3] == '4')
|
| - aix64_flag = 1;
|
| - else if (arg[2] == 'r' && arg[3] == 't' && arg[4] == 'l')
|
| - aixrtl_flag = 1;
|
| - break;
|
| -#endif
|
| -
|
| case 'd':
|
| if (!strcmp (arg, "-debug"))
|
| {
|
| @@ -1122,6 +1523,20 @@ main (int argc, char **argv)
|
| }
|
| break;
|
|
|
| + case 'f':
|
| + if (strcmp (arg, "-flto") == 0 || strcmp (arg, "-fwhopr") == 0)
|
| + {
|
| +#ifdef ENABLE_LTO
|
| + /* Do not pass LTO flag to the linker. */
|
| + ld1--;
|
| + ld2--;
|
| +#else
|
| + error ("LTO support has not been enabled in this "
|
| + "configuration");
|
| +#endif
|
| + }
|
| + break;
|
| +
|
| case 'l':
|
| if (first_file)
|
| {
|
| @@ -1150,7 +1565,9 @@ main (int argc, char **argv)
|
| #else
|
| #if LINK_ELIMINATE_DUPLICATE_LDIRECTORIES
|
| case 'L':
|
| - if (is_in_args (arg, (const char **) ld1_argv, ld1-1))
|
| + if (is_in_args (arg,
|
| + CONST_CAST2 (const char **, char **, ld1_argv),
|
| + ld1 - 1))
|
| --ld1;
|
| break;
|
| #endif /* LINK_ELIMINATE_DUPLICATE_LDIRECTORIES */
|
| @@ -1215,6 +1632,8 @@ main (int argc, char **argv)
|
| ld1--;
|
| ld2--;
|
| }
|
| + else if (strncmp (arg, "--sysroot=", 10) == 0)
|
| + target_system_root = arg + 10;
|
| break;
|
| }
|
| }
|
| @@ -1258,18 +1677,34 @@ main (int argc, char **argv)
|
| }
|
|
|
| /* The AIX linker will discard static constructors in object files if
|
| - nothing else in the file is referenced, so look at them first. */
|
| + nothing else in the file is referenced, so look at them first. Unless
|
| + we are building a shared object, ignore the eh frame tables, as we
|
| + would otherwise reference them all, hence drag all the corresponding
|
| + objects even if nothing else is referenced. */
|
| {
|
| - const char **export_object_lst = (const char **)object_lst;
|
| + const char **export_object_lst
|
| + = CONST_CAST2 (const char **, char **, object_lst);
|
|
|
| - while (export_object_lst < object)
|
| - scan_prog_file (*export_object_lst++, PASS_OBJ);
|
| - }
|
| - {
|
| struct id *list = libs.first;
|
|
|
| + /* Compute the filter to use from the current one, do scan, then adjust
|
| + the "current" filter to remove what we just included here. This will
|
| + control whether we need a first pass link later on or not, and what
|
| + will remain to be scanned there. */
|
| +
|
| + scanfilter this_filter = ld1_filter;
|
| +#if HAVE_AS_REF
|
| + if (!shared_obj)
|
| + this_filter &= ~SCAN_DWEH;
|
| +#endif
|
| +
|
| + while (export_object_lst < object)
|
| + scan_prog_file (*export_object_lst++, PASS_OBJ, this_filter);
|
| +
|
| for (; list; list = list->next)
|
| - scan_prog_file (list->name, PASS_FIRST);
|
| + scan_prog_file (list->name, PASS_FIRST, this_filter);
|
| +
|
| + ld1_filter = ld1_filter & ~this_filter;
|
| }
|
|
|
| if (exports.first)
|
| @@ -1340,42 +1775,48 @@ main (int argc, char **argv)
|
| }
|
|
|
| /* Load the program, searching all libraries and attempting to provide
|
| - undefined symbols from repository information. */
|
| -
|
| - /* On AIX we do this later. */
|
| -#ifndef COLLECT_EXPORT_LIST
|
| - do_tlink (ld1_argv, object_lst);
|
| -#endif
|
| + undefined symbols from repository information.
|
|
|
| - /* If -r or they will be run via some other method, do not build the
|
| + 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
|
| - /* Do the link we avoided above if we are exiting. */
|
| + {
|
| + bool early_exit
|
| + = rflag || (! DO_COLLECT_EXPORT_LIST && ! do_collecting);
|
| +
|
| + /* Perform the first pass link now, if we're about to exit or if we need
|
| + to scan for things we haven't collected yet before pursuing further.
|
| +
|
| + On AIX, the latter typically includes nothing for shared objects or
|
| + frame tables for an executable, out of what the required early scan on
|
| + objects and libraries has performed above. In the !shared_obj case, we
|
| + expect the relevant tables to be dragged together with their associated
|
| + functions from precise cross reference insertions by the compiler. */
|
| +
|
| + if (early_exit || ld1_filter != SCAN_NOTHING)
|
| do_tlink (ld1_argv, object_lst);
|
|
|
| - /* But make sure we delete the export file we may have created. */
|
| - if (export_file != 0 && export_file[0])
|
| - maybe_unlink (export_file);
|
| + if (early_exit)
|
| + {
|
| +#ifdef COLLECT_EXPORT_LIST
|
| + /* Make sure we delete the export file we may have created. */
|
| + if (export_file != 0 && export_file[0])
|
| + maybe_unlink (export_file);
|
| #endif
|
| - maybe_unlink (c_file);
|
| - maybe_unlink (o_file);
|
| - return 0;
|
| - }
|
| + if (lto_mode != LTO_MODE_NONE)
|
| + maybe_run_lto_and_relink (ld1_argv, object_lst, object, false);
|
|
|
| - /* 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. */
|
| + maybe_unlink (c_file);
|
| + maybe_unlink (o_file);
|
| + return 0;
|
| + }
|
| + }
|
|
|
| - /* On AIX we already scanned for global constructors/destructors. */
|
| -#ifndef COLLECT_EXPORT_LIST
|
| - scan_prog_file (output_file, PASS_FIRST);
|
| -#endif
|
| + /* Unless we have done it all already, examine the namelist and search for
|
| + static constructors and destructors to call. Write the constructor and
|
| + destructor tables to a .s file and reload. */
|
| +
|
| + if (ld1_filter != SCAN_NOTHING)
|
| + scan_prog_file (output_file, PASS_FIRST, ld1_filter);
|
|
|
| #ifdef SCAN_LIBRARIES
|
| scan_libraries (output_file);
|
| @@ -1383,11 +1824,23 @@ main (int argc, char **argv)
|
|
|
| if (debug)
|
| {
|
| - notice ("%d constructor(s) found\n", constructors.number);
|
| - notice ("%d destructor(s) found\n", destructors.number);
|
| - notice ("%d frame table(s) found\n", frame_tables.number);
|
| + notice_translated (ngettext ("%d constructor found\n",
|
| + "%d constructors found\n",
|
| + constructors.number),
|
| + constructors.number);
|
| + notice_translated (ngettext ("%d destructor found\n",
|
| + "%d destructors found\n",
|
| + destructors.number),
|
| + destructors.number);
|
| + notice_translated (ngettext("%d frame table found\n",
|
| + "%d frame tables found\n",
|
| + frame_tables.number),
|
| + frame_tables.number);
|
| }
|
|
|
| + /* If the scan exposed nothing of special interest, there's no need to
|
| + generate the glue code and relink so return now. */
|
| +
|
| if (constructors.number == 0 && destructors.number == 0
|
| && frame_tables.number == 0
|
| #if defined (SCAN_LIBRARIES) || defined (COLLECT_EXPORT_LIST)
|
| @@ -1398,15 +1851,20 @@ main (int argc, char **argv)
|
| #endif
|
| )
|
| {
|
| -#ifdef COLLECT_EXPORT_LIST
|
| - /* Do tlink without additional code generation. */
|
| - do_tlink (ld1_argv, object_lst);
|
| -#endif
|
| + /* Do tlink without additional code generation now if we didn't
|
| + do it earlier for scanning purposes. */
|
| + if (ld1_filter == SCAN_NOTHING)
|
| + do_tlink (ld1_argv, object_lst);
|
| +
|
| + if (lto_mode)
|
| + maybe_run_lto_and_relink (ld1_argv, object_lst, object, false);
|
| +
|
| /* Strip now if it was requested on the command line. */
|
| if (strip_flag)
|
| {
|
| char **real_strip_argv = XCNEWVEC (char *, 3);
|
| - const char ** strip_argv = (const char **) real_strip_argv;
|
| + const char ** strip_argv = CONST_CAST2 (const char **, char **,
|
| + real_strip_argv);
|
|
|
| strip_argv[0] = strip_file_name;
|
| strip_argv[1] = output_file;
|
| @@ -1494,13 +1952,19 @@ main (int argc, char **argv)
|
| #ifdef COLLECT_EXPORT_LIST
|
| /* On AIX we must call tlink because of possible templates resolution. */
|
| do_tlink (ld2_argv, object_lst);
|
| +
|
| + if (lto_mode)
|
| + maybe_run_lto_and_relink (ld2_argv, object_lst, object, false);
|
| #else
|
| /* Otherwise, simply call ld because tlink is already done. */
|
| - fork_execute ("ld", ld2_argv);
|
| + if (lto_mode)
|
| + maybe_run_lto_and_relink (ld2_argv, object_lst, object, true);
|
| + else
|
| + 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);
|
| + scan_prog_file (output_file, PASS_SECOND, SCAN_ALL);
|
| #endif
|
|
|
| maybe_unlink (c_file);
|
| @@ -1564,7 +2028,7 @@ do_wait (const char *prog, struct pex_obj *pex)
|
|
|
| struct pex_obj *
|
| collect_execute (const char *prog, char **argv, const char *outname,
|
| - const char *errname)
|
| + const char *errname, int flags)
|
| {
|
| struct pex_obj *pex;
|
| const char *errmsg;
|
| @@ -1640,7 +2104,7 @@ collect_execute (const char *prog, char **argv, const char *outname,
|
| if (pex == NULL)
|
| fatal_perror ("pex_init failed");
|
|
|
| - errmsg = pex_run (pex, PEX_LAST | PEX_SEARCH, argv[0], argv, outname,
|
| + errmsg = pex_run (pex, flags, argv[0], argv, outname,
|
| errname, &err);
|
| if (errmsg != NULL)
|
| {
|
| @@ -1664,7 +2128,7 @@ fork_execute (const char *prog, char **argv)
|
| {
|
| struct pex_obj *pex;
|
|
|
| - pex = collect_execute (prog, argv, NULL, NULL);
|
| + pex = collect_execute (prog, argv, NULL, NULL, PEX_LAST | PEX_SEARCH);
|
| do_wait (prog, pex);
|
| }
|
|
|
| @@ -1679,6 +2143,17 @@ maybe_unlink (const char *file)
|
| notice ("[Leaving %s]\n", file);
|
| }
|
|
|
| +/* Call maybe_unlink on the NULL-terminated list, FILE_LIST. */
|
| +
|
| +static void
|
| +maybe_unlink_list (char **file_list)
|
| +{
|
| + char **tmp = file_list;
|
| +
|
| + while (*tmp)
|
| + maybe_unlink (*(tmp++));
|
| +}
|
| +
|
|
|
| static long sequence_number = 0;
|
|
|
| @@ -2073,34 +2548,71 @@ write_aix_file (FILE *stream, struct id *list)
|
|
|
| #ifdef OBJECT_FORMAT_NONE
|
|
|
| -/* Generic version to scan the name list of the loaded program for
|
| - the symbols g++ uses for static constructors and destructors.
|
| +/* Check to make sure the file is an LTO object file. */
|
|
|
| - The constructor table begins at __CTOR_LIST__ and contains a count
|
| - of the number of pointers (or -1 if the constructors are built in a
|
| - separate section by the linker), followed by the pointers to the
|
| - constructor functions, terminated with a null pointer. The
|
| - destructor table has the same format, and begins at __DTOR_LIST__. */
|
| +static bool
|
| +maybe_lto_object_file (const char *prog_name)
|
| +{
|
| + FILE *f;
|
| + unsigned char buf[4];
|
| + int i;
|
| +
|
| + static unsigned char elfmagic[4] = { 0x7f, 'E', 'L', 'F' };
|
| + static unsigned char coffmagic[2] = { 0x4c, 0x01 };
|
| + static unsigned char machomagic[4][4] = {
|
| + { 0xcf, 0xfa, 0xed, 0xfe },
|
| + { 0xce, 0xfa, 0xed, 0xfe },
|
| + { 0xfe, 0xed, 0xfa, 0xcf },
|
| + { 0xfe, 0xed, 0xfa, 0xce }
|
| + };
|
| +
|
| + f = fopen (prog_name, "rb");
|
| + if (f == NULL)
|
| + return false;
|
| + if (fread (buf, sizeof (buf), 1, f) != 1)
|
| + buf[0] = 0;
|
| + fclose (f);
|
| +
|
| + if (memcmp (buf, elfmagic, sizeof (elfmagic)) == 0
|
| + || memcmp (buf, coffmagic, sizeof (coffmagic)) == 0)
|
| + return true;
|
| + for (i = 0; i < 4; i++)
|
| + if (memcmp (buf, machomagic[i], sizeof (machomagic[i])) == 0)
|
| + return true;
|
| +
|
| + return false;
|
| +}
|
| +
|
| +/* Generic version to scan the name list of the loaded program for
|
| + the symbols g++ uses for static constructors and destructors. */
|
|
|
| static void
|
| -scan_prog_file (const char *prog_name, enum pass which_pass)
|
| +scan_prog_file (const char *prog_name, scanpass which_pass,
|
| + scanfilter filter)
|
| {
|
| void (*int_handler) (int);
|
| #ifdef SIGQUIT
|
| void (*quit_handler) (int);
|
| #endif
|
| char *real_nm_argv[4];
|
| - const char **nm_argv = (const char **) real_nm_argv;
|
| + const char **nm_argv = CONST_CAST2 (const char **, char**, real_nm_argv);
|
| int argc = 0;
|
| struct pex_obj *pex;
|
| const char *errmsg;
|
| int err;
|
| char *p, buf[1024];
|
| FILE *inf;
|
| + int found_lto = 0;
|
|
|
| if (which_pass == PASS_SECOND)
|
| return;
|
|
|
| + /* LTO objects must be in a known format. This check prevents
|
| + us from accepting an archive containing LTO objects, which
|
| + gcc cannnot currently handle. */
|
| + if (which_pass == PASS_LTOINFO && !maybe_lto_object_file (prog_name))
|
| + return;
|
| +
|
| /* If we do not have an `nm', complain. */
|
| if (nm_file_name == 0)
|
| fatal ("cannot find 'nm'");
|
| @@ -2131,7 +2643,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
|
| if (pex == NULL)
|
| fatal_perror ("pex_init failed");
|
|
|
| - errmsg = pex_run (pex, 0, nm_file_name, real_nm_argv, NULL, NULL, &err);
|
| + errmsg = pex_run (pex, 0, nm_file_name, real_nm_argv, NULL, HOST_BIT_BUCKET,
|
| + &err);
|
| if (errmsg != NULL)
|
| {
|
| if (err != 0)
|
| @@ -2153,7 +2666,12 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
|
| fatal_perror ("can't open nm output");
|
|
|
| if (debug)
|
| - fprintf (stderr, "\nnm output with constructors/destructors.\n");
|
| + {
|
| + if (which_pass == PASS_LTOINFO)
|
| + fprintf (stderr, "\nnm output with LTO info marker symbol.\n");
|
| + else
|
| + fprintf (stderr, "\nnm output with constructors/destructors.\n");
|
| + }
|
|
|
| /* Read each line of nm output. */
|
| while (fgets (buf, sizeof buf, inf) != (char *) 0)
|
| @@ -2161,8 +2679,36 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
|
| int ch, ch2;
|
| char *name, *end;
|
|
|
| + if (debug)
|
| + fprintf (stderr, "\t%s\n", buf);
|
| +
|
| + if (which_pass == PASS_LTOINFO)
|
| + {
|
| + if (found_lto)
|
| + continue;
|
| +
|
| + /* Look for the LTO info marker symbol, and add filename to
|
| + the LTO objects list if found. */
|
| + for (p = buf; (ch = *p) != '\0' && ch != '\n'; p++)
|
| + if (ch == ' ' && p[1] == '_' && p[2] == '_'
|
| + && (strncmp (p + (p[3] == '_' ? 2 : 1), "__gnu_lto_v1", 12) == 0)
|
| + && ISSPACE (p[p[3] == '_' ? 14 : 13]))
|
| + {
|
| + add_lto_object (<o_objects, prog_name);
|
| +
|
| + /* We need to read all the input, so we can't just
|
| + return here. But we can avoid useless work. */
|
| + found_lto = 1;
|
| +
|
| + break;
|
| + }
|
| +
|
| + continue;
|
| + }
|
| +
|
| /* If it contains a constructor or destructor name, add the name
|
| - to the appropriate list. */
|
| + to the appropriate list unless this is a kind of symbol we're
|
| + not supposed to even consider. */
|
|
|
| for (p = buf; (ch = *p) != '\0' && ch != '\n' && ch != '_'; p++)
|
| if (ch == ' ' && p[1] == 'U' && p[2] == ' ')
|
| @@ -2183,16 +2729,22 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
|
| switch (is_ctor_dtor (name))
|
| {
|
| case SYM_CTOR:
|
| + if (! (filter & SCAN_CTOR))
|
| + break;
|
| if (which_pass != PASS_LIB)
|
| add_to_list (&constructors, name);
|
| break;
|
|
|
| case SYM_DTOR:
|
| + if (! (filter & SCAN_DTOR))
|
| + break;
|
| if (which_pass != PASS_LIB)
|
| add_to_list (&destructors, name);
|
| break;
|
|
|
| case SYM_INIT:
|
| + if (! (filter & SCAN_INIT))
|
| + break;
|
| if (which_pass != PASS_LIB)
|
| fatal ("init function found in object %s", prog_name);
|
| #ifndef LD_INIT_SWITCH
|
| @@ -2201,6 +2753,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
|
| break;
|
|
|
| case SYM_FINI:
|
| + if (! (filter & SCAN_FINI))
|
| + break;
|
| if (which_pass != PASS_LIB)
|
| fatal ("fini function found in object %s", prog_name);
|
| #ifndef LD_FINI_SWITCH
|
| @@ -2209,6 +2763,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
|
| break;
|
|
|
| case SYM_DWEH:
|
| + if (! (filter & SCAN_DWEH))
|
| + break;
|
| if (which_pass != PASS_LIB)
|
| add_to_list (&frame_tables, name);
|
| break;
|
| @@ -2216,9 +2772,6 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
|
| default: /* not a constructor or destructor */
|
| continue;
|
| }
|
| -
|
| - if (debug)
|
| - fprintf (stderr, "\t%s\n", buf);
|
| }
|
|
|
| if (debug)
|
| @@ -2248,7 +2801,7 @@ scan_libraries (const char *prog_name)
|
| void (*quit_handler) (int);
|
| #endif
|
| char *real_ldd_argv[4];
|
| - const char **ldd_argv = (const char **) real_ldd_argv;
|
| + const char **ldd_argv = CONST_CAST2 (const char **, char **, real_ldd_argv);
|
| int argc = 0;
|
| struct pex_obj *pex;
|
| const char *errmsg;
|
| @@ -2353,7 +2906,7 @@ scan_libraries (const char *prog_name)
|
| /* Now iterate through the library list adding their symbols to
|
| the list. */
|
| for (list = libraries.first; list; list = list->next)
|
| - scan_prog_file (list->name, PASS_LIB);
|
| + scan_prog_file (list->name, PASS_LIB, SCAN_ALL);
|
| }
|
|
|
| #endif /* LDD_SUFFIX */
|
| @@ -2404,7 +2957,7 @@ scan_libraries (const char *prog_name)
|
| # define GCC_SYMZERO(X) 0
|
|
|
| /* 0757 = U803XTOCMAGIC (AIX 4.3) and 0767 = U64_TOCMAGIC (AIX V5) */
|
| -#ifdef _AIX51
|
| +#if TARGET_AIX_VERSION >= 51
|
| # define GCC_CHECK_HDR(X) \
|
| ((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \
|
| || (HEADER (X).f_magic == 0767 && aix64_flag))
|
| @@ -2443,9 +2996,19 @@ static int ignore_library (const char *);
|
| static int
|
| ignore_library (const char *name)
|
| {
|
| - const char *const *p = &aix_std_libs[0];
|
| - while (*p++ != NULL)
|
| - if (! strcmp (name, *p)) return 1;
|
| + const char *const *p;
|
| + size_t length;
|
| +
|
| + if (target_system_root[0] != '\0')
|
| + {
|
| + length = strlen (target_system_root);
|
| + if (strncmp (name, target_system_root, length) != 0)
|
| + return 0;
|
| + name += length;
|
| + }
|
| + for (p = &aix_std_libs[0]; *p != NULL; ++p)
|
| + if (strcmp (name, *p) == 0)
|
| + return 1;
|
| return 0;
|
| }
|
| #endif /* COLLECT_EXPORT_LIST */
|
| @@ -2455,16 +3018,11 @@ extern char *ldgetname (LDFILE *, GCC_SYMENT *);
|
| #endif
|
|
|
| /* COFF version to scan the name list of the loaded program for
|
| - the symbols g++ uses for static constructors and destructors.
|
| -
|
| - The constructor table begins at __CTOR_LIST__ and contains a count
|
| - of the number of pointers (or -1 if the constructors are built in a
|
| - separate section by the linker), followed by the pointers to the
|
| - constructor functions, terminated with a null pointer. The
|
| - destructor table has the same format, and begins at __DTOR_LIST__. */
|
| + the symbols g++ uses for static constructors and destructors. */
|
|
|
| static void
|
| -scan_prog_file (const char *prog_name, enum pass which_pass)
|
| +scan_prog_file (const char *prog_name, scanpass which_pass,
|
| + scanfilter filter)
|
| {
|
| LDFILE *ldptr = NULL;
|
| int sym_index, sym_count;
|
| @@ -2528,6 +3086,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
|
| switch (is_ctor_dtor (name))
|
| {
|
| case SYM_CTOR:
|
| + if (! (filter & SCAN_CTOR))
|
| + break;
|
| if (! is_shared)
|
| add_to_list (&constructors, name);
|
| #if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
|
| @@ -2537,6 +3097,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
|
| break;
|
|
|
| case SYM_DTOR:
|
| + if (! (filter & SCAN_DTOR))
|
| + break;
|
| if (! is_shared)
|
| add_to_list (&destructors, name);
|
| #if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
|
| @@ -2547,6 +3109,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
|
|
|
| #ifdef COLLECT_EXPORT_LIST
|
| case SYM_INIT:
|
| + if (! (filter & SCAN_INIT))
|
| + break;
|
| #ifndef LD_INIT_SWITCH
|
| if (is_shared)
|
| add_to_list (&constructors, name);
|
| @@ -2554,6 +3118,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
|
| break;
|
|
|
| case SYM_FINI:
|
| + if (! (filter & SCAN_FINI))
|
| + break;
|
| #ifndef LD_INIT_SWITCH
|
| if (is_shared)
|
| add_to_list (&destructors, name);
|
| @@ -2562,6 +3128,8 @@ scan_prog_file (const char *prog_name, enum pass which_pass)
|
| #endif
|
|
|
| case SYM_DWEH:
|
| + if (! (filter & SCAN_DWEH))
|
| + break;
|
| if (! is_shared)
|
| add_to_list (&frame_tables, name);
|
| #if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
|
|
|