xref: /dragonfly/contrib/gcc-8.0/gcc/collect2.c (revision 58e805e6)
138fd1498Szrj /* Collect static initialization info into data structures that can be
238fd1498Szrj    traversed by C++ initialization and finalization routines.
338fd1498Szrj    Copyright (C) 1992-2018 Free Software Foundation, Inc.
438fd1498Szrj    Contributed by Chris Smith (csmith@convex.com).
538fd1498Szrj    Heavily modified by Michael Meissner (meissner@cygnus.com),
638fd1498Szrj    Per Bothner (bothner@cygnus.com), and John Gilmore (gnu@cygnus.com).
738fd1498Szrj 
838fd1498Szrj This file is part of GCC.
938fd1498Szrj 
1038fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
1138fd1498Szrj the terms of the GNU General Public License as published by the Free
1238fd1498Szrj Software Foundation; either version 3, or (at your option) any later
1338fd1498Szrj version.
1438fd1498Szrj 
1538fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1638fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1738fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1838fd1498Szrj for more details.
1938fd1498Szrj 
2038fd1498Szrj You should have received a copy of the GNU General Public License
2138fd1498Szrj along with GCC; see the file COPYING3.  If not see
2238fd1498Szrj <http://www.gnu.org/licenses/>.  */
2338fd1498Szrj 
2438fd1498Szrj 
2538fd1498Szrj /* Build tables of static constructors and destructors and run ld.  */
2638fd1498Szrj 
2738fd1498Szrj #include "config.h"
2838fd1498Szrj #include "system.h"
2938fd1498Szrj #include "coretypes.h"
3038fd1498Szrj #include "tm.h"
3138fd1498Szrj #include "filenames.h"
3238fd1498Szrj #include "file-find.h"
3338fd1498Szrj 
3438fd1498Szrj /* TARGET_64BIT may be defined to use driver specific functionality. */
3538fd1498Szrj #undef TARGET_64BIT
3638fd1498Szrj #define TARGET_64BIT TARGET_64BIT_DEFAULT
3738fd1498Szrj 
3838fd1498Szrj #ifndef LIBRARY_PATH_ENV
3938fd1498Szrj #define LIBRARY_PATH_ENV "LIBRARY_PATH"
4038fd1498Szrj #endif
4138fd1498Szrj 
4238fd1498Szrj #define COLLECT
4338fd1498Szrj 
4438fd1498Szrj #include "collect2.h"
4538fd1498Szrj #include "collect2-aix.h"
4638fd1498Szrj #include "collect-utils.h"
4738fd1498Szrj #include "diagnostic.h"
4838fd1498Szrj #include "demangle.h"
4938fd1498Szrj #include "obstack.h"
5038fd1498Szrj #include "intl.h"
5138fd1498Szrj #include "version.h"
5238fd1498Szrj 
5338fd1498Szrj /* On certain systems, we have code that works by scanning the object file
5438fd1498Szrj    directly.  But this code uses system-specific header files and library
5538fd1498Szrj    functions, so turn it off in a cross-compiler.  Likewise, the names of
5638fd1498Szrj    the utilities are not correct for a cross-compiler; we have to hope that
5738fd1498Szrj    cross-versions are in the proper directories.  */
5838fd1498Szrj 
5938fd1498Szrj #ifdef CROSS_DIRECTORY_STRUCTURE
6038fd1498Szrj #ifndef CROSS_AIX_SUPPORT
6138fd1498Szrj #undef OBJECT_FORMAT_COFF
6238fd1498Szrj #endif
6338fd1498Szrj #undef MD_EXEC_PREFIX
6438fd1498Szrj #undef REAL_LD_FILE_NAME
6538fd1498Szrj #undef REAL_NM_FILE_NAME
6638fd1498Szrj #undef REAL_STRIP_FILE_NAME
6738fd1498Szrj #endif
6838fd1498Szrj 
6938fd1498Szrj /* If we cannot use a special method, use the ordinary one:
7038fd1498Szrj    run nm to find what symbols are present.
7138fd1498Szrj    In a cross-compiler, this means you need a cross nm,
7238fd1498Szrj    but that is not quite as unpleasant as special headers.  */
7338fd1498Szrj 
7438fd1498Szrj #if !defined (OBJECT_FORMAT_COFF)
7538fd1498Szrj #define OBJECT_FORMAT_NONE
7638fd1498Szrj #endif
7738fd1498Szrj 
7838fd1498Szrj #ifdef OBJECT_FORMAT_COFF
7938fd1498Szrj 
8038fd1498Szrj #ifndef CROSS_DIRECTORY_STRUCTURE
8138fd1498Szrj #include <a.out.h>
8238fd1498Szrj #include <ar.h>
8338fd1498Szrj 
8438fd1498Szrj #ifdef UMAX
8538fd1498Szrj #include <sgs.h>
8638fd1498Szrj #endif
8738fd1498Szrj 
8838fd1498Szrj /* Many versions of ldfcn.h define these.  */
8938fd1498Szrj #ifdef FREAD
9038fd1498Szrj #undef FREAD
9138fd1498Szrj #undef FWRITE
9238fd1498Szrj #endif
9338fd1498Szrj 
9438fd1498Szrj #include <ldfcn.h>
9538fd1498Szrj #endif
9638fd1498Szrj 
9738fd1498Szrj /* Some systems have an ISCOFF macro, but others do not.  In some cases
9838fd1498Szrj    the macro may be wrong.  MY_ISCOFF is defined in tm.h files for machines
9938fd1498Szrj    that either do not have an ISCOFF macro in /usr/include or for those
10038fd1498Szrj    where it is wrong.  */
10138fd1498Szrj 
10238fd1498Szrj #ifndef MY_ISCOFF
10338fd1498Szrj #define MY_ISCOFF(X) ISCOFF (X)
10438fd1498Szrj #endif
10538fd1498Szrj 
10638fd1498Szrj #endif /* OBJECT_FORMAT_COFF */
10738fd1498Szrj 
10838fd1498Szrj #ifdef OBJECT_FORMAT_NONE
10938fd1498Szrj 
11038fd1498Szrj /* Default flags to pass to nm.  */
11138fd1498Szrj #ifndef NM_FLAGS
11238fd1498Szrj #define NM_FLAGS "-n"
11338fd1498Szrj #endif
11438fd1498Szrj 
11538fd1498Szrj #endif /* OBJECT_FORMAT_NONE */
11638fd1498Szrj 
11738fd1498Szrj /* Some systems use __main in a way incompatible with its use in gcc, in these
11838fd1498Szrj    cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
11938fd1498Szrj    give the same symbol without quotes for an alternative entry point.  */
12038fd1498Szrj #ifndef NAME__MAIN
12138fd1498Szrj #define NAME__MAIN "__main"
12238fd1498Szrj #endif
12338fd1498Szrj 
12438fd1498Szrj /* This must match tree.h.  */
12538fd1498Szrj #define DEFAULT_INIT_PRIORITY 65535
12638fd1498Szrj 
12738fd1498Szrj #ifndef COLLECT_SHARED_INIT_FUNC
12838fd1498Szrj #define COLLECT_SHARED_INIT_FUNC(STREAM, FUNC) \
12938fd1498Szrj   fprintf ((STREAM), "void _GLOBAL__DI() {\n\t%s();\n}\n", (FUNC))
13038fd1498Szrj #endif
13138fd1498Szrj #ifndef COLLECT_SHARED_FINI_FUNC
13238fd1498Szrj #define COLLECT_SHARED_FINI_FUNC(STREAM, FUNC) \
13338fd1498Szrj   fprintf ((STREAM), "void _GLOBAL__DD() {\n\t%s();\n}\n", (FUNC))
13438fd1498Szrj #endif
13538fd1498Szrj 
13638fd1498Szrj #ifdef LDD_SUFFIX
13738fd1498Szrj #define SCAN_LIBRARIES
13838fd1498Szrj #endif
13938fd1498Szrj 
14038fd1498Szrj #ifndef SHLIB_SUFFIX
14138fd1498Szrj #define SHLIB_SUFFIX ".so"
14238fd1498Szrj #endif
14338fd1498Szrj 
14438fd1498Szrj #ifdef USE_COLLECT2
14538fd1498Szrj int do_collecting = 1;
14638fd1498Szrj #else
14738fd1498Szrj int do_collecting = 0;
14838fd1498Szrj #endif
14938fd1498Szrj 
15038fd1498Szrj /* Cook up an always defined indication of whether we proceed the
15138fd1498Szrj    "EXPORT_LIST" way.  */
15238fd1498Szrj 
15338fd1498Szrj #ifdef COLLECT_EXPORT_LIST
15438fd1498Szrj #define DO_COLLECT_EXPORT_LIST 1
15538fd1498Szrj #else
15638fd1498Szrj #define DO_COLLECT_EXPORT_LIST 0
15738fd1498Szrj #endif
15838fd1498Szrj 
15938fd1498Szrj /* Nonzero if we should suppress the automatic demangling of identifiers
16038fd1498Szrj    in linker error messages.  Set from COLLECT_NO_DEMANGLE.  */
16138fd1498Szrj int no_demangle;
16238fd1498Szrj 
16338fd1498Szrj /* Linked lists of constructor and destructor names.  */
16438fd1498Szrj 
16538fd1498Szrj struct id
16638fd1498Szrj {
16738fd1498Szrj   struct id *next;
16838fd1498Szrj   int sequence;
16938fd1498Szrj   char name[1];
17038fd1498Szrj };
17138fd1498Szrj 
17238fd1498Szrj struct head
17338fd1498Szrj {
17438fd1498Szrj   struct id *first;
17538fd1498Szrj   struct id *last;
17638fd1498Szrj   int number;
17738fd1498Szrj };
17838fd1498Szrj 
17938fd1498Szrj static int rflag;			/* true if -r */
18038fd1498Szrj static int strip_flag;			/* true if -s */
18138fd1498Szrj #ifdef COLLECT_EXPORT_LIST
18238fd1498Szrj static int export_flag;                 /* true if -bE */
18338fd1498Szrj static int aix64_flag;			/* true if -b64 */
18438fd1498Szrj static int aixrtl_flag;			/* true if -brtl */
18538fd1498Szrj static int aixlazy_flag;               /* true if -blazy */
18638fd1498Szrj #endif
18738fd1498Szrj 
18838fd1498Szrj enum lto_mode_d {
18938fd1498Szrj   LTO_MODE_NONE,			/* Not doing LTO.  */
19038fd1498Szrj   LTO_MODE_LTO,				/* Normal LTO.  */
19138fd1498Szrj   LTO_MODE_WHOPR			/* WHOPR.  */
19238fd1498Szrj };
19338fd1498Szrj 
19438fd1498Szrj /* Current LTO mode.  */
19538fd1498Szrj #ifdef ENABLE_LTO
19638fd1498Szrj static enum lto_mode_d lto_mode = LTO_MODE_WHOPR;
19738fd1498Szrj #else
19838fd1498Szrj static enum lto_mode_d lto_mode = LTO_MODE_NONE;
19938fd1498Szrj #endif
20038fd1498Szrj 
20138fd1498Szrj bool helpflag;			/* true if --help */
20238fd1498Szrj 
20338fd1498Szrj static int shared_obj;			/* true if -shared */
204*58e805e6Szrj static int static_obj;			/* true if -static */
20538fd1498Szrj 
20638fd1498Szrj static const char *c_file;		/* <xxx>.c for constructor/destructor list.  */
20738fd1498Szrj static const char *o_file;		/* <xxx>.o for constructor/destructor list.  */
20838fd1498Szrj #ifdef COLLECT_EXPORT_LIST
20938fd1498Szrj static const char *export_file;		/* <xxx>.x for AIX export list.  */
21038fd1498Szrj #endif
21138fd1498Szrj static char **lto_o_files;		/* Output files for LTO.  */
21238fd1498Szrj const char *ldout;			/* File for ld stdout.  */
21338fd1498Szrj const char *lderrout;			/* File for ld stderr.  */
21438fd1498Szrj static const char *output_file;		/* Output file for ld.  */
21538fd1498Szrj static const char *nm_file_name;	/* pathname of nm */
21638fd1498Szrj #ifdef LDD_SUFFIX
21738fd1498Szrj static const char *ldd_file_name;	/* pathname of ldd (or equivalent) */
21838fd1498Szrj #endif
21938fd1498Szrj static const char *strip_file_name;		/* pathname of strip */
22038fd1498Szrj const char *c_file_name;		/* pathname of gcc */
22138fd1498Szrj static char *initname, *fininame;	/* names of init and fini funcs */
22238fd1498Szrj 
22338fd1498Szrj 
22438fd1498Szrj #ifdef TARGET_AIX_VERSION
22538fd1498Szrj static char *aix_shared_initname;
22638fd1498Szrj static char *aix_shared_fininame;       /* init/fini names as per the scheme
22738fd1498Szrj 					   described in config/rs6000/aix.h */
22838fd1498Szrj #endif
22938fd1498Szrj 
23038fd1498Szrj static struct head constructors;	/* list of constructors found */
23138fd1498Szrj static struct head destructors;		/* list of destructors found */
23238fd1498Szrj #ifdef COLLECT_EXPORT_LIST
23338fd1498Szrj static struct head exports;		/* list of exported symbols */
23438fd1498Szrj #endif
23538fd1498Szrj static struct head frame_tables;	/* list of frame unwind info tables */
23638fd1498Szrj 
23738fd1498Szrj bool at_file_supplied;		/* Whether to use @file arguments */
23838fd1498Szrj 
23938fd1498Szrj struct obstack temporary_obstack;
24038fd1498Szrj char * temporary_firstobj;
24138fd1498Szrj 
24238fd1498Szrj /* A string that must be prepended to a target OS path in order to find
24338fd1498Szrj    it on the host system.  */
24438fd1498Szrj #ifdef TARGET_SYSTEM_ROOT
24538fd1498Szrj static const char *target_system_root = TARGET_SYSTEM_ROOT;
24638fd1498Szrj #else
24738fd1498Szrj static const char *target_system_root = "";
24838fd1498Szrj #endif
24938fd1498Szrj 
25038fd1498Szrj /* Whether we may unlink the output file, which should be set as soon as we
25138fd1498Szrj    know we have successfully produced it.  This is typically useful to prevent
25238fd1498Szrj    blindly attempting to unlink a read-only output that the target linker
25338fd1498Szrj    would leave untouched.  */
25438fd1498Szrj bool may_unlink_output_file = false;
25538fd1498Szrj 
25638fd1498Szrj #ifdef COLLECT_EXPORT_LIST
25738fd1498Szrj /* Lists to keep libraries to be scanned for global constructors/destructors.  */
25838fd1498Szrj static struct head libs;                    /* list of libraries */
259*58e805e6Szrj static struct head static_libs;             /* list of statically linked libraries */
26038fd1498Szrj static struct path_prefix cmdline_lib_dirs; /* directories specified with -L */
26138fd1498Szrj static struct path_prefix libpath_lib_dirs; /* directories in LIBPATH */
26238fd1498Szrj static struct path_prefix *libpaths[3] = {&cmdline_lib_dirs,
26338fd1498Szrj 					  &libpath_lib_dirs, NULL};
26438fd1498Szrj #endif
26538fd1498Szrj 
26638fd1498Szrj /* List of names of object files containing LTO information.
26738fd1498Szrj    These are a subset of the object file names appearing on the
26838fd1498Szrj    command line, and must be identical, in the sense of pointer
26938fd1498Szrj    equality, with the names passed to maybe_run_lto_and_relink().  */
27038fd1498Szrj 
27138fd1498Szrj struct lto_object
27238fd1498Szrj {
27338fd1498Szrj   const char *name;		/* Name of object file.  */
27438fd1498Szrj   struct lto_object *next;	/* Next in linked list.  */
27538fd1498Szrj };
27638fd1498Szrj 
27738fd1498Szrj struct lto_object_list
27838fd1498Szrj {
27938fd1498Szrj   struct lto_object *first;	/* First list element.  */
28038fd1498Szrj   struct lto_object *last;	/* Last list element.  */
28138fd1498Szrj };
28238fd1498Szrj 
28338fd1498Szrj static struct lto_object_list lto_objects;
28438fd1498Szrj 
28538fd1498Szrj /* Special kinds of symbols that a name may denote.  */
28638fd1498Szrj 
28738fd1498Szrj enum symkind {
28838fd1498Szrj   SYM_REGULAR = 0,  /* nothing special  */
28938fd1498Szrj 
29038fd1498Szrj   SYM_CTOR = 1,  /* constructor */
29138fd1498Szrj   SYM_DTOR = 2,  /* destructor  */
29238fd1498Szrj   SYM_INIT = 3,  /* shared object routine that calls all the ctors  */
29338fd1498Szrj   SYM_FINI = 4,  /* shared object routine that calls all the dtors  */
29438fd1498Szrj   SYM_DWEH = 5,  /* DWARF exception handling table  */
29538fd1498Szrj   SYM_AIXI = 6,
29638fd1498Szrj   SYM_AIXD = 7
29738fd1498Szrj };
29838fd1498Szrj 
29938fd1498Szrj const char tool_name[] = "collect2";
30038fd1498Szrj 
30138fd1498Szrj static symkind is_ctor_dtor (const char *);
30238fd1498Szrj 
30338fd1498Szrj static void handler (int);
30438fd1498Szrj static void maybe_unlink_list (char **);
30538fd1498Szrj static void add_to_list (struct head *, const char *);
30638fd1498Szrj static int extract_init_priority (const char *);
30738fd1498Szrj static void sort_ids (struct head *);
30838fd1498Szrj static void write_list (FILE *, const char *, struct id *);
30938fd1498Szrj #ifdef COLLECT_EXPORT_LIST
31038fd1498Szrj static void dump_list (FILE *, const char *, struct id *);
31138fd1498Szrj #endif
31238fd1498Szrj #if 0
31338fd1498Szrj static void dump_prefix_list (FILE *, const char *, struct prefix_list *);
31438fd1498Szrj #endif
31538fd1498Szrj static void write_list_with_asm (FILE *, const char *, struct id *);
31638fd1498Szrj static void write_c_file (FILE *, const char *);
31738fd1498Szrj static void write_c_file_stat (FILE *, const char *);
31838fd1498Szrj #ifndef LD_INIT_SWITCH
31938fd1498Szrj static void write_c_file_glob (FILE *, const char *);
32038fd1498Szrj #endif
32138fd1498Szrj #ifdef SCAN_LIBRARIES
32238fd1498Szrj static void scan_libraries (const char *);
32338fd1498Szrj #endif
32438fd1498Szrj #ifdef COLLECT_EXPORT_LIST
32538fd1498Szrj static int is_in_list (const char *, struct id *);
32638fd1498Szrj static void write_aix_file (FILE *, struct id *);
32738fd1498Szrj static char *resolve_lib_name (const char *);
32838fd1498Szrj #endif
32938fd1498Szrj static char *extract_string (const char **);
33038fd1498Szrj static void post_ld_pass (bool);
33138fd1498Szrj static void process_args (int *argcp, char **argv);
33238fd1498Szrj 
33338fd1498Szrj /* Enumerations describing which pass this is for scanning the
33438fd1498Szrj    program file ...  */
33538fd1498Szrj 
33638fd1498Szrj enum scanpass {
33738fd1498Szrj   PASS_FIRST,				/* without constructors */
33838fd1498Szrj   PASS_OBJ,				/* individual objects */
33938fd1498Szrj   PASS_LIB,				/* looking for shared libraries */
34038fd1498Szrj   PASS_SECOND,				/* with constructors linked in */
34138fd1498Szrj   PASS_LTOINFO				/* looking for objects with LTO info */
34238fd1498Szrj };
34338fd1498Szrj 
34438fd1498Szrj /* ... and which kinds of symbols are to be considered.  */
34538fd1498Szrj 
34638fd1498Szrj enum scanfilter_masks {
34738fd1498Szrj   SCAN_NOTHING = 0,
34838fd1498Szrj 
34938fd1498Szrj   SCAN_CTOR = 1 << SYM_CTOR,
35038fd1498Szrj   SCAN_DTOR = 1 << SYM_DTOR,
35138fd1498Szrj   SCAN_INIT = 1 << SYM_INIT,
35238fd1498Szrj   SCAN_FINI = 1 << SYM_FINI,
35338fd1498Szrj   SCAN_DWEH = 1 << SYM_DWEH,
35438fd1498Szrj   SCAN_AIXI = 1 << SYM_AIXI,
35538fd1498Szrj   SCAN_AIXD = 1 << SYM_AIXD,
35638fd1498Szrj   SCAN_ALL  = ~0
35738fd1498Szrj };
35838fd1498Szrj 
35938fd1498Szrj /* This type is used for parameters and variables which hold
36038fd1498Szrj    combinations of the flags in enum scanfilter_masks.  */
36138fd1498Szrj typedef int scanfilter;
36238fd1498Szrj 
36338fd1498Szrj /* Scan the name list of the loaded program for the symbols g++ uses for
36438fd1498Szrj    static constructors and destructors.
36538fd1498Szrj 
36638fd1498Szrj    The SCANPASS argument tells which collect processing pass this is for and
36738fd1498Szrj    the SCANFILTER argument tells which kinds of symbols to consider in this
36838fd1498Szrj    pass.  Symbols of a special kind not in the filter mask are considered as
36938fd1498Szrj    regular ones.
37038fd1498Szrj 
37138fd1498Szrj    The constructor table begins at __CTOR_LIST__ and contains a count of the
37238fd1498Szrj    number of pointers (or -1 if the constructors are built in a separate
37338fd1498Szrj    section by the linker), followed by the pointers to the constructor
37438fd1498Szrj    functions, terminated with a null pointer.  The destructor table has the
37538fd1498Szrj    same format, and begins at __DTOR_LIST__.  */
37638fd1498Szrj 
37738fd1498Szrj static void scan_prog_file (const char *, scanpass, scanfilter);
37838fd1498Szrj 
37938fd1498Szrj 
38038fd1498Szrj /* Delete tempfiles and exit function.  */
38138fd1498Szrj 
38238fd1498Szrj void
tool_cleanup(bool from_signal)38338fd1498Szrj tool_cleanup (bool from_signal)
38438fd1498Szrj {
38538fd1498Szrj   if (c_file != 0 && c_file[0])
38638fd1498Szrj     maybe_unlink (c_file);
38738fd1498Szrj 
38838fd1498Szrj   if (o_file != 0 && o_file[0])
38938fd1498Szrj     maybe_unlink (o_file);
39038fd1498Szrj 
39138fd1498Szrj #ifdef COLLECT_EXPORT_LIST
39238fd1498Szrj   if (export_file != 0 && export_file[0])
39338fd1498Szrj     maybe_unlink (export_file);
39438fd1498Szrj #endif
39538fd1498Szrj 
39638fd1498Szrj   if (lto_o_files)
39738fd1498Szrj     maybe_unlink_list (lto_o_files);
39838fd1498Szrj 
39938fd1498Szrj   if (ldout != 0 && ldout[0])
40038fd1498Szrj     {
40138fd1498Szrj       if (!from_signal)
40238fd1498Szrj 	dump_ld_file (ldout, stdout);
40338fd1498Szrj       maybe_unlink (ldout);
40438fd1498Szrj     }
40538fd1498Szrj 
40638fd1498Szrj   if (lderrout != 0 && lderrout[0])
40738fd1498Szrj     {
40838fd1498Szrj       if (!from_signal)
40938fd1498Szrj 	dump_ld_file (lderrout, stderr);
41038fd1498Szrj       maybe_unlink (lderrout);
41138fd1498Szrj     }
41238fd1498Szrj }
41338fd1498Szrj 
41438fd1498Szrj static void
collect_atexit(void)41538fd1498Szrj collect_atexit (void)
41638fd1498Szrj {
41738fd1498Szrj   tool_cleanup (false);
41838fd1498Szrj }
41938fd1498Szrj 
42038fd1498Szrj static void
handler(int signo)42138fd1498Szrj handler (int signo)
42238fd1498Szrj {
42338fd1498Szrj   tool_cleanup (true);
42438fd1498Szrj 
42538fd1498Szrj   signal (signo, SIG_DFL);
42638fd1498Szrj   raise (signo);
42738fd1498Szrj }
42838fd1498Szrj /* Notify user of a non-error, without translating the format string.  */
42938fd1498Szrj void
notice_translated(const char * cmsgid,...)43038fd1498Szrj notice_translated (const char *cmsgid, ...)
43138fd1498Szrj {
43238fd1498Szrj   va_list ap;
43338fd1498Szrj 
43438fd1498Szrj   va_start (ap, cmsgid);
43538fd1498Szrj   vfprintf (stderr, cmsgid, ap);
43638fd1498Szrj   va_end (ap);
43738fd1498Szrj }
43838fd1498Szrj 
43938fd1498Szrj int
file_exists(const char * name)44038fd1498Szrj file_exists (const char *name)
44138fd1498Szrj {
44238fd1498Szrj   return access (name, R_OK) == 0;
44338fd1498Szrj }
44438fd1498Szrj 
44538fd1498Szrj /* Parse a reasonable subset of shell quoting syntax.  */
44638fd1498Szrj 
44738fd1498Szrj static char *
extract_string(const char ** pp)44838fd1498Szrj extract_string (const char **pp)
44938fd1498Szrj {
45038fd1498Szrj   const char *p = *pp;
45138fd1498Szrj   int backquote = 0;
45238fd1498Szrj   int inside = 0;
45338fd1498Szrj 
45438fd1498Szrj   for (;;)
45538fd1498Szrj     {
45638fd1498Szrj       char c = *p;
45738fd1498Szrj       if (c == '\0')
45838fd1498Szrj 	break;
45938fd1498Szrj       ++p;
46038fd1498Szrj       if (backquote)
46138fd1498Szrj 	obstack_1grow (&temporary_obstack, c);
46238fd1498Szrj       else if (! inside && c == ' ')
46338fd1498Szrj 	break;
46438fd1498Szrj       else if (! inside && c == '\\')
46538fd1498Szrj 	backquote = 1;
46638fd1498Szrj       else if (c == '\'')
46738fd1498Szrj 	inside = !inside;
46838fd1498Szrj       else
46938fd1498Szrj 	obstack_1grow (&temporary_obstack, c);
47038fd1498Szrj     }
47138fd1498Szrj 
47238fd1498Szrj   obstack_1grow (&temporary_obstack, '\0');
47338fd1498Szrj   *pp = p;
47438fd1498Szrj   return XOBFINISH (&temporary_obstack, char *);
47538fd1498Szrj }
47638fd1498Szrj 
47738fd1498Szrj void
dump_ld_file(const char * name,FILE * to)47838fd1498Szrj dump_ld_file (const char *name, FILE *to)
47938fd1498Szrj {
48038fd1498Szrj   FILE *stream = fopen (name, "r");
48138fd1498Szrj 
48238fd1498Szrj   if (stream == 0)
48338fd1498Szrj     return;
48438fd1498Szrj   while (1)
48538fd1498Szrj     {
48638fd1498Szrj       int c;
48738fd1498Szrj       while (c = getc (stream),
48838fd1498Szrj 	     c != EOF && (ISIDNUM (c) || c == '$' || c == '.'))
48938fd1498Szrj 	obstack_1grow (&temporary_obstack, c);
49038fd1498Szrj       if (obstack_object_size (&temporary_obstack) > 0)
49138fd1498Szrj 	{
49238fd1498Szrj 	  const char *word, *p;
49338fd1498Szrj 	  char *result;
49438fd1498Szrj 	  obstack_1grow (&temporary_obstack, '\0');
49538fd1498Szrj 	  word = XOBFINISH (&temporary_obstack, const char *);
49638fd1498Szrj 
49738fd1498Szrj 	  if (*word == '.')
49838fd1498Szrj 	    ++word, putc ('.', to);
49938fd1498Szrj 	  p = word;
50038fd1498Szrj 	  if (!strncmp (p, USER_LABEL_PREFIX, strlen (USER_LABEL_PREFIX)))
50138fd1498Szrj 	    p += strlen (USER_LABEL_PREFIX);
50238fd1498Szrj 
50338fd1498Szrj #ifdef HAVE_LD_DEMANGLE
50438fd1498Szrj 	  result = 0;
50538fd1498Szrj #else
50638fd1498Szrj 	  if (no_demangle)
50738fd1498Szrj 	    result = 0;
50838fd1498Szrj 	  else
50938fd1498Szrj 	    result = cplus_demangle (p, DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE);
51038fd1498Szrj #endif
51138fd1498Szrj 
51238fd1498Szrj 	  if (result)
51338fd1498Szrj 	    {
51438fd1498Szrj 	      int diff;
51538fd1498Szrj 	      fputs (result, to);
51638fd1498Szrj 
51738fd1498Szrj 	      diff = strlen (word) - strlen (result);
51838fd1498Szrj 	      while (diff > 0 && c == ' ')
51938fd1498Szrj 		--diff, putc (' ', to);
52038fd1498Szrj 	      if (diff < 0 && c == ' ')
52138fd1498Szrj 		{
52238fd1498Szrj 		  while (diff < 0 && c == ' ')
52338fd1498Szrj 		    ++diff, c = getc (stream);
52438fd1498Szrj 		  if (!ISSPACE (c))
52538fd1498Szrj 		    {
52638fd1498Szrj 		      /* Make sure we output at least one space, or
52738fd1498Szrj 			 the demangled symbol name will run into
52838fd1498Szrj 			 whatever text follows.  */
52938fd1498Szrj 		      putc (' ', to);
53038fd1498Szrj 		    }
53138fd1498Szrj 		}
53238fd1498Szrj 
53338fd1498Szrj 	      free (result);
53438fd1498Szrj 	    }
53538fd1498Szrj 	  else
53638fd1498Szrj 	    fputs (word, to);
53738fd1498Szrj 
53838fd1498Szrj 	  fflush (to);
53938fd1498Szrj 	  obstack_free (&temporary_obstack, temporary_firstobj);
54038fd1498Szrj 	}
54138fd1498Szrj       if (c == EOF)
54238fd1498Szrj 	break;
54338fd1498Szrj       putc (c, to);
54438fd1498Szrj     }
54538fd1498Szrj   fclose (stream);
54638fd1498Szrj }
54738fd1498Szrj 
54838fd1498Szrj /* Return the kind of symbol denoted by name S.  */
54938fd1498Szrj 
55038fd1498Szrj static symkind
is_ctor_dtor(const char * s)55138fd1498Szrj is_ctor_dtor (const char *s)
55238fd1498Szrj {
55338fd1498Szrj   struct names { const char *const name; const int len; symkind ret;
55438fd1498Szrj     const int two_underscores; };
55538fd1498Szrj 
55638fd1498Szrj   const struct names *p;
55738fd1498Szrj   int ch;
55838fd1498Szrj   const char *orig_s = s;
55938fd1498Szrj 
56038fd1498Szrj   static const struct names special[] = {
56138fd1498Szrj #ifndef NO_DOLLAR_IN_LABEL
56238fd1498Szrj     { "GLOBAL__I$", sizeof ("GLOBAL__I$")-1, SYM_CTOR, 0 },
56338fd1498Szrj     { "GLOBAL__D$", sizeof ("GLOBAL__D$")-1, SYM_DTOR, 0 },
56438fd1498Szrj #else
56538fd1498Szrj #ifndef NO_DOT_IN_LABEL
56638fd1498Szrj     { "GLOBAL__I.", sizeof ("GLOBAL__I.")-1, SYM_CTOR, 0 },
56738fd1498Szrj     { "GLOBAL__D.", sizeof ("GLOBAL__D.")-1, SYM_DTOR, 0 },
56838fd1498Szrj #endif /* NO_DOT_IN_LABEL */
56938fd1498Szrj #endif /* NO_DOLLAR_IN_LABEL */
57038fd1498Szrj     { "GLOBAL__I_", sizeof ("GLOBAL__I_")-1, SYM_CTOR, 0 },
57138fd1498Szrj     { "GLOBAL__D_", sizeof ("GLOBAL__D_")-1, SYM_DTOR, 0 },
57238fd1498Szrj     { "GLOBAL__F_", sizeof ("GLOBAL__F_")-1, SYM_DWEH, 0 },
57338fd1498Szrj     { "GLOBAL__FI_", sizeof ("GLOBAL__FI_")-1, SYM_INIT, 0 },
57438fd1498Szrj     { "GLOBAL__FD_", sizeof ("GLOBAL__FD_")-1, SYM_FINI, 0 },
57538fd1498Szrj #ifdef TARGET_AIX_VERSION
57638fd1498Szrj     { "GLOBAL__AIXI_", sizeof ("GLOBAL__AIXI_")-1, SYM_AIXI, 0 },
57738fd1498Szrj     { "GLOBAL__AIXD_", sizeof ("GLOBAL__AIXD_")-1, SYM_AIXD, 0 },
57838fd1498Szrj #endif
57938fd1498Szrj     { NULL, 0, SYM_REGULAR, 0 }
58038fd1498Szrj   };
58138fd1498Szrj 
58238fd1498Szrj   while ((ch = *s) == '_')
58338fd1498Szrj     ++s;
58438fd1498Szrj 
58538fd1498Szrj   if (s == orig_s)
58638fd1498Szrj     return SYM_REGULAR;
58738fd1498Szrj 
58838fd1498Szrj   for (p = &special[0]; p->len > 0; p++)
58938fd1498Szrj     {
59038fd1498Szrj       if (ch == p->name[0]
59138fd1498Szrj 	  && (!p->two_underscores || ((s - orig_s) >= 2))
59238fd1498Szrj 	  && strncmp (s, p->name, p->len) == 0)
59338fd1498Szrj 	{
59438fd1498Szrj 	  return p->ret;
59538fd1498Szrj 	}
59638fd1498Szrj     }
59738fd1498Szrj   return SYM_REGULAR;
59838fd1498Szrj }
59938fd1498Szrj 
60038fd1498Szrj /* We maintain two prefix lists: one from COMPILER_PATH environment variable
60138fd1498Szrj    and one from the PATH variable.  */
60238fd1498Szrj 
60338fd1498Szrj static struct path_prefix cpath, path;
60438fd1498Szrj 
60538fd1498Szrj #ifdef CROSS_DIRECTORY_STRUCTURE
60638fd1498Szrj /* This is the name of the target machine.  We use it to form the name
60738fd1498Szrj    of the files to execute.  */
60838fd1498Szrj 
60938fd1498Szrj static const char *const target_machine = TARGET_MACHINE;
61038fd1498Szrj #endif
61138fd1498Szrj 
61238fd1498Szrj /* Search for NAME using prefix list PPREFIX.  We only look for executable
61338fd1498Szrj    files.
61438fd1498Szrj 
61538fd1498Szrj    Return 0 if not found, otherwise return its name, allocated with malloc.  */
61638fd1498Szrj 
61738fd1498Szrj #if defined (OBJECT_FORMAT_NONE) || defined (OBJECT_FORMAT_COFF)
61838fd1498Szrj 
61938fd1498Szrj /* Add an entry for the object file NAME to object file list LIST.
62038fd1498Szrj    New entries are added at the end of the list. The original pointer
62138fd1498Szrj    value of NAME is preserved, i.e., no string copy is performed.  */
62238fd1498Szrj 
62338fd1498Szrj static void
add_lto_object(struct lto_object_list * list,const char * name)62438fd1498Szrj add_lto_object (struct lto_object_list *list, const char *name)
62538fd1498Szrj {
62638fd1498Szrj   struct lto_object *n = XNEW (struct lto_object);
62738fd1498Szrj   n->name = name;
62838fd1498Szrj   n->next = NULL;
62938fd1498Szrj 
63038fd1498Szrj   if (list->last)
63138fd1498Szrj     list->last->next = n;
63238fd1498Szrj   else
63338fd1498Szrj     list->first = n;
63438fd1498Szrj 
63538fd1498Szrj   list->last = n;
63638fd1498Szrj }
63738fd1498Szrj #endif
63838fd1498Szrj 
63938fd1498Szrj 
64038fd1498Szrj /* Perform a link-time recompilation and relink if any of the object
64138fd1498Szrj    files contain LTO info.  The linker command line LTO_LD_ARGV
64238fd1498Szrj    represents the linker command that would produce a final executable
64338fd1498Szrj    without the use of LTO. OBJECT_LST is a vector of object file names
64438fd1498Szrj    appearing in LTO_LD_ARGV that are to be considered for link-time
64538fd1498Szrj    recompilation, where OBJECT is a pointer to the last valid element.
64638fd1498Szrj    (This awkward convention avoids an impedance mismatch with the
64738fd1498Szrj    usage of similarly-named variables in main().)  The elements of
64838fd1498Szrj    OBJECT_LST must be identical, i.e., pointer equal, to the
64938fd1498Szrj    corresponding arguments in LTO_LD_ARGV.
65038fd1498Szrj 
65138fd1498Szrj    Upon entry, at least one linker run has been performed without the
65238fd1498Szrj    use of any LTO info that might be present.  Any recompilations
65338fd1498Szrj    necessary for template instantiations have been performed, and
65438fd1498Szrj    initializer/finalizer tables have been created if needed and
65538fd1498Szrj    included in the linker command line LTO_LD_ARGV. If any of the
65638fd1498Szrj    object files contain LTO info, we run the LTO back end on all such
65738fd1498Szrj    files, and perform the final link with the LTO back end output
65838fd1498Szrj    substituted for the LTO-optimized files.  In some cases, a final
65938fd1498Szrj    link with all link-time generated code has already been performed,
66038fd1498Szrj    so there is no need to relink if no LTO info is found.  In other
66138fd1498Szrj    cases, our caller has not produced the final executable, and is
66238fd1498Szrj    relying on us to perform the required link whether LTO info is
66338fd1498Szrj    present or not.  In that case, the FORCE argument should be true.
66438fd1498Szrj    Note that the linker command line argument LTO_LD_ARGV passed into
66538fd1498Szrj    this function may be modified in place.  */
66638fd1498Szrj 
66738fd1498Szrj static void
maybe_run_lto_and_relink(char ** lto_ld_argv,char ** object_lst,const char ** object,bool force)66838fd1498Szrj maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst,
66938fd1498Szrj 			  const char **object, bool force)
67038fd1498Szrj {
67138fd1498Szrj   const char **object_file = CONST_CAST2 (const char **, char **, object_lst);
67238fd1498Szrj 
67338fd1498Szrj   int num_lto_c_args = 1;    /* Allow space for the terminating NULL.  */
67438fd1498Szrj 
67538fd1498Szrj   while (object_file < object)
67638fd1498Szrj   {
67738fd1498Szrj     /* If file contains LTO info, add it to the list of LTO objects.  */
67838fd1498Szrj     scan_prog_file (*object_file++, PASS_LTOINFO, SCAN_ALL);
67938fd1498Szrj 
68038fd1498Szrj     /* Increment the argument count by the number of object file arguments
68138fd1498Szrj        we will add.  An upper bound suffices, so just count all of the
68238fd1498Szrj        object files regardless of whether they contain LTO info.  */
68338fd1498Szrj     num_lto_c_args++;
68438fd1498Szrj   }
68538fd1498Szrj 
68638fd1498Szrj   if (lto_objects.first)
68738fd1498Szrj     {
68838fd1498Szrj       char **lto_c_argv;
68938fd1498Szrj       const char **lto_c_ptr;
69038fd1498Szrj       char **p;
69138fd1498Szrj       char **lto_o_ptr;
69238fd1498Szrj       struct lto_object *list;
69338fd1498Szrj       char *lto_wrapper = getenv ("COLLECT_LTO_WRAPPER");
69438fd1498Szrj       struct pex_obj *pex;
69538fd1498Szrj       const char *prog = "lto-wrapper";
69638fd1498Szrj       int lto_ld_argv_size = 0;
69738fd1498Szrj       char **out_lto_ld_argv;
69838fd1498Szrj       int out_lto_ld_argv_size;
69938fd1498Szrj       size_t num_files;
70038fd1498Szrj 
70138fd1498Szrj       if (!lto_wrapper)
70238fd1498Szrj 	fatal_error (input_location, "COLLECT_LTO_WRAPPER must be set");
70338fd1498Szrj 
70438fd1498Szrj       num_lto_c_args++;
70538fd1498Szrj 
70638fd1498Szrj       /* There is at least one object file containing LTO info,
70738fd1498Szrj          so we need to run the LTO back end and relink.
70838fd1498Szrj 
70938fd1498Szrj 	 To do so we build updated ld arguments with first
71038fd1498Szrj 	 LTO object replaced by all partitions and other LTO
71138fd1498Szrj 	 objects removed.  */
71238fd1498Szrj 
71338fd1498Szrj       lto_c_argv = (char **) xcalloc (sizeof (char *), num_lto_c_args);
71438fd1498Szrj       lto_c_ptr = CONST_CAST2 (const char **, char **, lto_c_argv);
71538fd1498Szrj 
71638fd1498Szrj       *lto_c_ptr++ = lto_wrapper;
71738fd1498Szrj 
71838fd1498Szrj       /* Add LTO objects to the wrapper command line.  */
71938fd1498Szrj       for (list = lto_objects.first; list; list = list->next)
72038fd1498Szrj 	*lto_c_ptr++ = list->name;
72138fd1498Szrj 
72238fd1498Szrj       *lto_c_ptr = NULL;
72338fd1498Szrj 
72438fd1498Szrj       /* Run the LTO back end.  */
72538fd1498Szrj       pex = collect_execute (prog, lto_c_argv, NULL, NULL, PEX_SEARCH,
72638fd1498Szrj 			     at_file_supplied);
72738fd1498Szrj       {
72838fd1498Szrj 	int c;
72938fd1498Szrj 	FILE *stream;
73038fd1498Szrj 	size_t i;
73138fd1498Szrj 	char *start, *end;
73238fd1498Szrj 
73338fd1498Szrj 	stream = pex_read_output (pex, 0);
73438fd1498Szrj 	gcc_assert (stream);
73538fd1498Szrj 
73638fd1498Szrj 	num_files = 0;
73738fd1498Szrj 	while ((c = getc (stream)) != EOF)
73838fd1498Szrj 	  {
73938fd1498Szrj 	    obstack_1grow (&temporary_obstack, c);
74038fd1498Szrj 	    if (c == '\n')
74138fd1498Szrj 	      ++num_files;
74238fd1498Szrj 	  }
74338fd1498Szrj 
74438fd1498Szrj 	lto_o_files = XNEWVEC (char *, num_files + 1);
74538fd1498Szrj 	lto_o_files[num_files] = NULL;
74638fd1498Szrj 	start = XOBFINISH (&temporary_obstack, char *);
74738fd1498Szrj 	for (i = 0; i < num_files; ++i)
74838fd1498Szrj 	  {
74938fd1498Szrj 	    end = start;
75038fd1498Szrj 	    while (*end != '\n')
75138fd1498Szrj 	      ++end;
75238fd1498Szrj 	    *end = '\0';
75338fd1498Szrj 
75438fd1498Szrj 	    lto_o_files[i] = xstrdup (start);
75538fd1498Szrj 
75638fd1498Szrj 	    start = end + 1;
75738fd1498Szrj 	  }
75838fd1498Szrj 
75938fd1498Szrj 	obstack_free (&temporary_obstack, temporary_firstobj);
76038fd1498Szrj       }
76138fd1498Szrj       do_wait (prog, pex);
76238fd1498Szrj       pex = NULL;
76338fd1498Szrj 
76438fd1498Szrj       /* Compute memory needed for new LD arguments.  At most number of original arguments
76538fd1498Szrj 	 plus number of partitions.  */
76638fd1498Szrj       for (lto_ld_argv_size = 0; lto_ld_argv[lto_ld_argv_size]; lto_ld_argv_size++)
76738fd1498Szrj 	;
76838fd1498Szrj       out_lto_ld_argv = XCNEWVEC (char *, num_files + lto_ld_argv_size + 1);
76938fd1498Szrj       out_lto_ld_argv_size = 0;
77038fd1498Szrj 
77138fd1498Szrj       /* After running the LTO back end, we will relink, substituting
77238fd1498Szrj 	 the LTO output for the object files that we submitted to the
77338fd1498Szrj 	 LTO. Here, we modify the linker command line for the relink.  */
77438fd1498Szrj 
77538fd1498Szrj       /* Copy all arguments until we find first LTO file.  */
77638fd1498Szrj       p = lto_ld_argv;
77738fd1498Szrj       while (*p != NULL)
77838fd1498Szrj         {
77938fd1498Szrj           for (list = lto_objects.first; list; list = list->next)
78038fd1498Szrj             if (*p == list->name) /* Note test for pointer equality!  */
78138fd1498Szrj 	      break;
78238fd1498Szrj 	  if (list)
78338fd1498Szrj 	    break;
78438fd1498Szrj 	  out_lto_ld_argv[out_lto_ld_argv_size++] = *p++;
78538fd1498Szrj         }
78638fd1498Szrj 
78738fd1498Szrj       /* Now insert all LTO partitions.  */
78838fd1498Szrj       lto_o_ptr = lto_o_files;
78938fd1498Szrj       while (*lto_o_ptr)
79038fd1498Szrj 	out_lto_ld_argv[out_lto_ld_argv_size++] = *lto_o_ptr++;
79138fd1498Szrj 
79238fd1498Szrj       /* ... and copy the rest.  */
79338fd1498Szrj       while (*p != NULL)
79438fd1498Szrj         {
79538fd1498Szrj           for (list = lto_objects.first; list; list = list->next)
79638fd1498Szrj             if (*p == list->name) /* Note test for pointer equality!  */
79738fd1498Szrj 	      break;
79838fd1498Szrj 	  if (!list)
79938fd1498Szrj 	    out_lto_ld_argv[out_lto_ld_argv_size++] = *p;
80038fd1498Szrj 	  p++;
80138fd1498Szrj         }
80238fd1498Szrj       out_lto_ld_argv[out_lto_ld_argv_size++] = 0;
80338fd1498Szrj 
80438fd1498Szrj       /* Run the linker again, this time replacing the object files
80538fd1498Szrj          optimized by the LTO with the temporary file generated by the LTO.  */
80638fd1498Szrj       fork_execute ("ld", out_lto_ld_argv, HAVE_GNU_LD && at_file_supplied);
80738fd1498Szrj       post_ld_pass (true);
80838fd1498Szrj       free (lto_ld_argv);
80938fd1498Szrj 
81038fd1498Szrj       maybe_unlink_list (lto_o_files);
81138fd1498Szrj     }
81238fd1498Szrj   else if (force)
81338fd1498Szrj     {
81438fd1498Szrj       /* Our caller is relying on us to do the link
81538fd1498Szrj          even though there is no LTO back end work to be done.  */
81638fd1498Szrj       fork_execute ("ld", lto_ld_argv, HAVE_GNU_LD && at_file_supplied);
81738fd1498Szrj       post_ld_pass (false);
81838fd1498Szrj     }
81938fd1498Szrj   else
82038fd1498Szrj     post_ld_pass (true);
82138fd1498Szrj }
82238fd1498Szrj 
82338fd1498Szrj /* Main program.  */
82438fd1498Szrj 
82538fd1498Szrj int
main(int argc,char ** argv)82638fd1498Szrj main (int argc, char **argv)
82738fd1498Szrj {
82838fd1498Szrj   enum linker_select
82938fd1498Szrj     {
83038fd1498Szrj       USE_DEFAULT_LD,
83138fd1498Szrj       USE_PLUGIN_LD,
83238fd1498Szrj       USE_GOLD_LD,
83338fd1498Szrj       USE_BFD_LD,
83438fd1498Szrj       USE_LD_MAX
83538fd1498Szrj     } selected_linker = USE_DEFAULT_LD;
83638fd1498Szrj   static const char *const ld_suffixes[USE_LD_MAX] =
83738fd1498Szrj     {
83838fd1498Szrj       "ld",
83938fd1498Szrj       PLUGIN_LD_SUFFIX,
84038fd1498Szrj       "ld.gold",
84138fd1498Szrj       "ld.bfd"
84238fd1498Szrj     };
84338fd1498Szrj   static const char *const real_ld_suffix = "real-ld";
84438fd1498Szrj   static const char *const collect_ld_suffix = "collect-ld";
84538fd1498Szrj   static const char *const nm_suffix	= "nm";
84638fd1498Szrj   static const char *const gnm_suffix	= "gnm";
84738fd1498Szrj #ifdef LDD_SUFFIX
84838fd1498Szrj   static const char *const ldd_suffix	= LDD_SUFFIX;
84938fd1498Szrj #endif
85038fd1498Szrj   static const char *const strip_suffix = "strip";
85138fd1498Szrj   static const char *const gstrip_suffix = "gstrip";
85238fd1498Szrj 
85338fd1498Szrj   const char *full_ld_suffixes[USE_LD_MAX];
85438fd1498Szrj #ifdef CROSS_DIRECTORY_STRUCTURE
85538fd1498Szrj   /* If we look for a program in the compiler directories, we just use
85638fd1498Szrj      the short name, since these directories are already system-specific.
85738fd1498Szrj      But it we look for a program in the system directories, we need to
85838fd1498Szrj      qualify the program name with the target machine.  */
85938fd1498Szrj 
86038fd1498Szrj   const char *const full_nm_suffix =
86138fd1498Szrj     concat (target_machine, "-", nm_suffix, NULL);
86238fd1498Szrj   const char *const full_gnm_suffix =
86338fd1498Szrj     concat (target_machine, "-", gnm_suffix, NULL);
86438fd1498Szrj #ifdef LDD_SUFFIX
86538fd1498Szrj   const char *const full_ldd_suffix =
86638fd1498Szrj     concat (target_machine, "-", ldd_suffix, NULL);
86738fd1498Szrj #endif
86838fd1498Szrj   const char *const full_strip_suffix =
86938fd1498Szrj     concat (target_machine, "-", strip_suffix, NULL);
87038fd1498Szrj   const char *const full_gstrip_suffix =
87138fd1498Szrj     concat (target_machine, "-", gstrip_suffix, NULL);
87238fd1498Szrj #else
87338fd1498Szrj #ifdef LDD_SUFFIX
87438fd1498Szrj   const char *const full_ldd_suffix	= ldd_suffix;
87538fd1498Szrj #endif
87638fd1498Szrj   const char *const full_nm_suffix	= nm_suffix;
87738fd1498Szrj   const char *const full_gnm_suffix	= gnm_suffix;
87838fd1498Szrj   const char *const full_strip_suffix	= strip_suffix;
87938fd1498Szrj   const char *const full_gstrip_suffix	= gstrip_suffix;
88038fd1498Szrj #endif /* CROSS_DIRECTORY_STRUCTURE */
88138fd1498Szrj 
88238fd1498Szrj   const char *arg;
88338fd1498Szrj   FILE *outf;
88438fd1498Szrj #ifdef COLLECT_EXPORT_LIST
88538fd1498Szrj   FILE *exportf;
88638fd1498Szrj #endif
88738fd1498Szrj   const char *ld_file_name;
88838fd1498Szrj   const char *p;
88938fd1498Szrj   char **c_argv;
89038fd1498Szrj   const char **c_ptr;
89138fd1498Szrj   char **ld1_argv;
89238fd1498Szrj   const char **ld1;
89338fd1498Szrj   bool use_plugin = false;
89438fd1498Szrj   bool use_collect_ld = false;
89538fd1498Szrj 
89638fd1498Szrj   /* The kinds of symbols we will have to consider when scanning the
89738fd1498Szrj      outcome of a first pass link.  This is ALL to start with, then might
89838fd1498Szrj      be adjusted before getting to the first pass link per se, typically on
89938fd1498Szrj      AIX where we perform an early scan of objects and libraries to fetch
90038fd1498Szrj      the list of global ctors/dtors and make sure they are not garbage
90138fd1498Szrj      collected.  */
90238fd1498Szrj   scanfilter ld1_filter = SCAN_ALL;
90338fd1498Szrj 
90438fd1498Szrj   char **ld2_argv;
90538fd1498Szrj   const char **ld2;
90638fd1498Szrj   char **object_lst;
90738fd1498Szrj   const char **object;
90838fd1498Szrj #ifdef TARGET_AIX_VERSION
90938fd1498Szrj   int object_nbr = argc;
91038fd1498Szrj #endif
91138fd1498Szrj   int first_file;
91238fd1498Szrj   int num_c_args;
91338fd1498Szrj   char **old_argv;
914*58e805e6Szrj #ifdef COLLECT_EXPORT_LIST
915*58e805e6Szrj   bool is_static = false;
916*58e805e6Szrj #endif
91738fd1498Szrj   int i;
91838fd1498Szrj 
91938fd1498Szrj   for (i = 0; i < USE_LD_MAX; i++)
92038fd1498Szrj     full_ld_suffixes[i]
92138fd1498Szrj #ifdef CROSS_DIRECTORY_STRUCTURE
92238fd1498Szrj       = concat (target_machine, "-", ld_suffixes[i], NULL);
92338fd1498Szrj #else
92438fd1498Szrj       = ld_suffixes[i];
92538fd1498Szrj #endif
92638fd1498Szrj 
92738fd1498Szrj   p = argv[0] + strlen (argv[0]);
92838fd1498Szrj   while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
92938fd1498Szrj     --p;
93038fd1498Szrj   progname = p;
93138fd1498Szrj 
93238fd1498Szrj   xmalloc_set_program_name (progname);
93338fd1498Szrj 
93438fd1498Szrj   old_argv = argv;
93538fd1498Szrj   expandargv (&argc, &argv);
93638fd1498Szrj   if (argv != old_argv)
93738fd1498Szrj     at_file_supplied = 1;
93838fd1498Szrj 
93938fd1498Szrj   process_args (&argc, argv);
94038fd1498Szrj 
94138fd1498Szrj   num_c_args = argc + 9;
94238fd1498Szrj 
94338fd1498Szrj #ifndef HAVE_LD_DEMANGLE
94438fd1498Szrj   no_demangle = !! getenv ("COLLECT_NO_DEMANGLE");
94538fd1498Szrj 
94638fd1498Szrj   /* Suppress demangling by the real linker, which may be broken.  */
94738fd1498Szrj   putenv (xstrdup ("COLLECT_NO_DEMANGLE=1"));
94838fd1498Szrj #endif
94938fd1498Szrj 
95038fd1498Szrj #if defined (COLLECT2_HOST_INITIALIZATION)
95138fd1498Szrj   /* Perform system dependent initialization, if necessary.  */
95238fd1498Szrj   COLLECT2_HOST_INITIALIZATION;
95338fd1498Szrj #endif
95438fd1498Szrj 
95538fd1498Szrj #ifdef SIGCHLD
95638fd1498Szrj   /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
95738fd1498Szrj      receive the signal.  A different setting is inheritable */
95838fd1498Szrj   signal (SIGCHLD, SIG_DFL);
95938fd1498Szrj #endif
96038fd1498Szrj 
96138fd1498Szrj   /* Unlock the stdio streams.  */
96238fd1498Szrj   unlock_std_streams ();
96338fd1498Szrj 
96438fd1498Szrj   gcc_init_libintl ();
96538fd1498Szrj 
96638fd1498Szrj   diagnostic_initialize (global_dc, 0);
96738fd1498Szrj 
96838fd1498Szrj   if (atexit (collect_atexit) != 0)
96938fd1498Szrj     fatal_error (input_location, "atexit failed");
97038fd1498Szrj 
97138fd1498Szrj   /* Do not invoke xcalloc before this point, since locale needs to be
97238fd1498Szrj      set first, in case a diagnostic is issued.  */
97338fd1498Szrj 
97438fd1498Szrj   ld1_argv = XCNEWVEC (char *, argc + 4);
97538fd1498Szrj   ld1 = CONST_CAST2 (const char **, char **, ld1_argv);
97638fd1498Szrj   ld2_argv = XCNEWVEC (char *, argc + 11);
97738fd1498Szrj   ld2 = CONST_CAST2 (const char **, char **, ld2_argv);
97838fd1498Szrj   object_lst = XCNEWVEC (char *, argc);
97938fd1498Szrj   object = CONST_CAST2 (const char **, char **, object_lst);
98038fd1498Szrj 
98138fd1498Szrj #ifdef DEBUG
98238fd1498Szrj   debug = 1;
98338fd1498Szrj #endif
98438fd1498Szrj 
98538fd1498Szrj   /* Parse command line early for instances of -debug.  This allows
98638fd1498Szrj      the debug flag to be set before functions like find_a_file()
98738fd1498Szrj      are called.  We also look for the -flto or -flto-partition=none flag to know
98838fd1498Szrj      what LTO mode we are in.  */
98938fd1498Szrj   {
99038fd1498Szrj     bool no_partition = false;
99138fd1498Szrj 
99238fd1498Szrj     for (i = 1; argv[i] != NULL; i ++)
99338fd1498Szrj       {
99438fd1498Szrj 	if (! strcmp (argv[i], "-debug"))
99538fd1498Szrj 	  debug = true;
99638fd1498Szrj         else if (! strcmp (argv[i], "-flto-partition=none"))
99738fd1498Szrj 	  no_partition = true;
99838fd1498Szrj 	else if (!strncmp (argv[i], "-fno-lto", 8))
99938fd1498Szrj 	  lto_mode = LTO_MODE_NONE;
100038fd1498Szrj         else if (! strcmp (argv[i], "-plugin"))
100138fd1498Szrj 	  {
100238fd1498Szrj 	    use_plugin = true;
100338fd1498Szrj 	    if (selected_linker == USE_DEFAULT_LD)
100438fd1498Szrj 	      selected_linker = USE_PLUGIN_LD;
100538fd1498Szrj 	  }
100638fd1498Szrj 	else if (strcmp (argv[i], "-fuse-ld=bfd") == 0)
100738fd1498Szrj 	  selected_linker = USE_BFD_LD;
100838fd1498Szrj 	else if (strcmp (argv[i], "-fuse-ld=gold") == 0)
100938fd1498Szrj 	  selected_linker = USE_GOLD_LD;
101038fd1498Szrj 
101138fd1498Szrj #ifdef COLLECT_EXPORT_LIST
101238fd1498Szrj 	/* These flags are position independent, although their order
101338fd1498Szrj 	   is important - subsequent flags override earlier ones. */
101438fd1498Szrj 	else if (strcmp (argv[i], "-b64") == 0)
101538fd1498Szrj 	    aix64_flag = 1;
101638fd1498Szrj 	/* -bexport:filename always needs the :filename */
101738fd1498Szrj 	else if (strncmp (argv[i], "-bE:", 4) == 0
101838fd1498Szrj 	      || strncmp (argv[i], "-bexport:", 9) == 0)
101938fd1498Szrj 	    export_flag = 1;
102038fd1498Szrj 	else if (strcmp (argv[i], "-brtl") == 0
102138fd1498Szrj 	      || strcmp (argv[i], "-bsvr4") == 0
102238fd1498Szrj 	      || strcmp (argv[i], "-G") == 0)
102338fd1498Szrj 	    aixrtl_flag = 1;
102438fd1498Szrj 	else if (strcmp (argv[i], "-bnortl") == 0)
102538fd1498Szrj 	    aixrtl_flag = 0;
102638fd1498Szrj 	else if (strcmp (argv[i], "-blazy") == 0)
102738fd1498Szrj 	    aixlazy_flag = 1;
102838fd1498Szrj #endif
102938fd1498Szrj       }
103038fd1498Szrj     verbose = debug;
103138fd1498Szrj     find_file_set_debug (debug);
103238fd1498Szrj     if (use_plugin)
103338fd1498Szrj       lto_mode = LTO_MODE_NONE;
103438fd1498Szrj     if (no_partition && lto_mode == LTO_MODE_WHOPR)
103538fd1498Szrj       lto_mode = LTO_MODE_LTO;
103638fd1498Szrj   }
103738fd1498Szrj 
103838fd1498Szrj #ifndef DEFAULT_A_OUT_NAME
103938fd1498Szrj   output_file = "a.out";
104038fd1498Szrj #else
104138fd1498Szrj   output_file = DEFAULT_A_OUT_NAME;
104238fd1498Szrj #endif
104338fd1498Szrj 
104438fd1498Szrj   obstack_begin (&temporary_obstack, 0);
104538fd1498Szrj   temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0);
104638fd1498Szrj 
104738fd1498Szrj #ifndef HAVE_LD_DEMANGLE
104838fd1498Szrj   current_demangling_style = auto_demangling;
104938fd1498Szrj #endif
105038fd1498Szrj   p = getenv ("COLLECT_GCC_OPTIONS");
105138fd1498Szrj   while (p && *p)
105238fd1498Szrj     {
105338fd1498Szrj       const char *q = extract_string (&p);
105438fd1498Szrj       if (*q == '-' && (q[1] == 'm' || q[1] == 'f'))
105538fd1498Szrj 	num_c_args++;
105638fd1498Szrj     }
105738fd1498Szrj   obstack_free (&temporary_obstack, temporary_firstobj);
105838fd1498Szrj 
105938fd1498Szrj   /* -fno-profile-arcs -fno-test-coverage -fno-branch-probabilities
106038fd1498Szrj      -fno-exceptions -w -fno-whole-program */
106138fd1498Szrj   num_c_args += 6;
106238fd1498Szrj 
106338fd1498Szrj   c_argv = XCNEWVEC (char *, num_c_args);
106438fd1498Szrj   c_ptr = CONST_CAST2 (const char **, char **, c_argv);
106538fd1498Szrj 
106638fd1498Szrj   if (argc < 2)
106738fd1498Szrj     fatal_error (input_location, "no arguments");
106838fd1498Szrj 
106938fd1498Szrj #ifdef SIGQUIT
107038fd1498Szrj   if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
107138fd1498Szrj     signal (SIGQUIT, handler);
107238fd1498Szrj #endif
107338fd1498Szrj   if (signal (SIGINT, SIG_IGN) != SIG_IGN)
107438fd1498Szrj     signal (SIGINT, handler);
107538fd1498Szrj #ifdef SIGALRM
107638fd1498Szrj   if (signal (SIGALRM, SIG_IGN) != SIG_IGN)
107738fd1498Szrj     signal (SIGALRM, handler);
107838fd1498Szrj #endif
107938fd1498Szrj #ifdef SIGHUP
108038fd1498Szrj   if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
108138fd1498Szrj     signal (SIGHUP, handler);
108238fd1498Szrj #endif
108338fd1498Szrj   if (signal (SIGSEGV, SIG_IGN) != SIG_IGN)
108438fd1498Szrj     signal (SIGSEGV, handler);
108538fd1498Szrj #ifdef SIGBUS
108638fd1498Szrj   if (signal (SIGBUS, SIG_IGN) != SIG_IGN)
108738fd1498Szrj     signal (SIGBUS, handler);
108838fd1498Szrj #endif
108938fd1498Szrj 
109038fd1498Szrj   /* Extract COMPILER_PATH and PATH into our prefix list.  */
109138fd1498Szrj   prefix_from_env ("COMPILER_PATH", &cpath);
109238fd1498Szrj   prefix_from_env ("PATH", &path);
109338fd1498Szrj 
109438fd1498Szrj   /* Try to discover a valid linker/nm/strip to use.  */
109538fd1498Szrj 
109638fd1498Szrj   /* Maybe we know the right file to use (if not cross).  */
109738fd1498Szrj   ld_file_name = 0;
109838fd1498Szrj #ifdef DEFAULT_LINKER
109938fd1498Szrj   if (selected_linker == USE_BFD_LD || selected_linker == USE_GOLD_LD)
110038fd1498Szrj     {
110138fd1498Szrj       char *linker_name;
110238fd1498Szrj # ifdef HOST_EXECUTABLE_SUFFIX
110338fd1498Szrj       int len = (sizeof (DEFAULT_LINKER)
110438fd1498Szrj 		 - sizeof (HOST_EXECUTABLE_SUFFIX));
110538fd1498Szrj       linker_name = NULL;
110638fd1498Szrj       if (len > 0)
110738fd1498Szrj 	{
110838fd1498Szrj 	  char *default_linker = xstrdup (DEFAULT_LINKER);
110938fd1498Szrj 	  /* Strip HOST_EXECUTABLE_SUFFIX if DEFAULT_LINKER contains
111038fd1498Szrj 	     HOST_EXECUTABLE_SUFFIX.  */
111138fd1498Szrj 	  if (! strcmp (&default_linker[len], HOST_EXECUTABLE_SUFFIX))
111238fd1498Szrj 	    {
111338fd1498Szrj 	      default_linker[len] = '\0';
111438fd1498Szrj 	      linker_name = concat (default_linker,
111538fd1498Szrj 				    &ld_suffixes[selected_linker][2],
111638fd1498Szrj 				    HOST_EXECUTABLE_SUFFIX, NULL);
111738fd1498Szrj 	    }
111838fd1498Szrj 	}
111938fd1498Szrj       if (linker_name == NULL)
112038fd1498Szrj # endif
112138fd1498Szrj       linker_name = concat (DEFAULT_LINKER,
112238fd1498Szrj 			    &ld_suffixes[selected_linker][2],
112338fd1498Szrj 			    NULL);
112438fd1498Szrj       if (access (linker_name, X_OK) == 0)
112538fd1498Szrj 	ld_file_name = linker_name;
112638fd1498Szrj     }
112738fd1498Szrj   if (ld_file_name == 0 && access (DEFAULT_LINKER, X_OK) == 0)
112838fd1498Szrj     ld_file_name = DEFAULT_LINKER;
112938fd1498Szrj   if (ld_file_name == 0)
113038fd1498Szrj #endif
113138fd1498Szrj #ifdef REAL_LD_FILE_NAME
113238fd1498Szrj   ld_file_name = find_a_file (&path, REAL_LD_FILE_NAME, X_OK);
113338fd1498Szrj   if (ld_file_name == 0)
113438fd1498Szrj #endif
113538fd1498Szrj   /* Search the (target-specific) compiler dirs for ld'.  */
113638fd1498Szrj   ld_file_name = find_a_file (&cpath, real_ld_suffix, X_OK);
113738fd1498Szrj   /* Likewise for `collect-ld'.  */
113838fd1498Szrj   if (ld_file_name == 0)
113938fd1498Szrj     {
114038fd1498Szrj       ld_file_name = find_a_file (&cpath, collect_ld_suffix, X_OK);
114138fd1498Szrj       use_collect_ld = ld_file_name != 0;
114238fd1498Szrj     }
114338fd1498Szrj   /* Search the compiler directories for `ld'.  We have protection against
114438fd1498Szrj      recursive calls in find_a_file.  */
114538fd1498Szrj   if (ld_file_name == 0)
114638fd1498Szrj     ld_file_name = find_a_file (&cpath, ld_suffixes[selected_linker], X_OK);
114738fd1498Szrj   /* Search the ordinary system bin directories
114838fd1498Szrj      for `ld' (if native linking) or `TARGET-ld' (if cross).  */
114938fd1498Szrj   if (ld_file_name == 0)
115038fd1498Szrj     ld_file_name = find_a_file (&path, full_ld_suffixes[selected_linker], X_OK);
115138fd1498Szrj 
115238fd1498Szrj #ifdef REAL_NM_FILE_NAME
115338fd1498Szrj   nm_file_name = find_a_file (&path, REAL_NM_FILE_NAME, X_OK);
115438fd1498Szrj   if (nm_file_name == 0)
115538fd1498Szrj #endif
115638fd1498Szrj   nm_file_name = find_a_file (&cpath, gnm_suffix, X_OK);
115738fd1498Szrj   if (nm_file_name == 0)
115838fd1498Szrj     nm_file_name = find_a_file (&path, full_gnm_suffix, X_OK);
115938fd1498Szrj   if (nm_file_name == 0)
116038fd1498Szrj     nm_file_name = find_a_file (&cpath, nm_suffix, X_OK);
116138fd1498Szrj   if (nm_file_name == 0)
116238fd1498Szrj     nm_file_name = find_a_file (&path, full_nm_suffix, X_OK);
116338fd1498Szrj 
116438fd1498Szrj #ifdef LDD_SUFFIX
116538fd1498Szrj   ldd_file_name = find_a_file (&cpath, ldd_suffix, X_OK);
116638fd1498Szrj   if (ldd_file_name == 0)
116738fd1498Szrj     ldd_file_name = find_a_file (&path, full_ldd_suffix, X_OK);
116838fd1498Szrj #endif
116938fd1498Szrj 
117038fd1498Szrj #ifdef REAL_STRIP_FILE_NAME
117138fd1498Szrj   strip_file_name = find_a_file (&path, REAL_STRIP_FILE_NAME, X_OK);
117238fd1498Szrj   if (strip_file_name == 0)
117338fd1498Szrj #endif
117438fd1498Szrj   strip_file_name = find_a_file (&cpath, gstrip_suffix, X_OK);
117538fd1498Szrj   if (strip_file_name == 0)
117638fd1498Szrj     strip_file_name = find_a_file (&path, full_gstrip_suffix, X_OK);
117738fd1498Szrj   if (strip_file_name == 0)
117838fd1498Szrj     strip_file_name = find_a_file (&cpath, strip_suffix, X_OK);
117938fd1498Szrj   if (strip_file_name == 0)
118038fd1498Szrj     strip_file_name = find_a_file (&path, full_strip_suffix, X_OK);
118138fd1498Szrj 
118238fd1498Szrj   /* Determine the full path name of the C compiler to use.  */
118338fd1498Szrj   c_file_name = getenv ("COLLECT_GCC");
118438fd1498Szrj   if (c_file_name == 0)
118538fd1498Szrj     {
118638fd1498Szrj #ifdef CROSS_DIRECTORY_STRUCTURE
118738fd1498Szrj       c_file_name = concat (target_machine, "-gcc", NULL);
118838fd1498Szrj #else
118938fd1498Szrj       c_file_name = "gcc";
119038fd1498Szrj #endif
119138fd1498Szrj     }
119238fd1498Szrj 
119338fd1498Szrj   p = find_a_file (&cpath, c_file_name, X_OK);
119438fd1498Szrj 
119538fd1498Szrj   /* Here it should be safe to use the system search path since we should have
119638fd1498Szrj      already qualified the name of the compiler when it is needed.  */
119738fd1498Szrj   if (p == 0)
119838fd1498Szrj     p = find_a_file (&path, c_file_name, X_OK);
119938fd1498Szrj 
120038fd1498Szrj   if (p)
120138fd1498Szrj     c_file_name = p;
120238fd1498Szrj 
120338fd1498Szrj   *ld1++ = *ld2++ = ld_file_name;
120438fd1498Szrj 
120538fd1498Szrj   /* Make temp file names.  */
120638fd1498Szrj   c_file = make_temp_file (".c");
120738fd1498Szrj   o_file = make_temp_file (".o");
120838fd1498Szrj #ifdef COLLECT_EXPORT_LIST
120938fd1498Szrj   export_file = make_temp_file (".x");
121038fd1498Szrj #endif
121138fd1498Szrj   if (!debug)
121238fd1498Szrj     {
121338fd1498Szrj       ldout = make_temp_file (".ld");
121438fd1498Szrj       lderrout = make_temp_file (".le");
121538fd1498Szrj     }
121638fd1498Szrj   *c_ptr++ = c_file_name;
121738fd1498Szrj   *c_ptr++ = "-x";
121838fd1498Szrj   *c_ptr++ = "c";
121938fd1498Szrj   *c_ptr++ = "-c";
122038fd1498Szrj   *c_ptr++ = "-o";
122138fd1498Szrj   *c_ptr++ = o_file;
122238fd1498Szrj 
122338fd1498Szrj #ifdef COLLECT_EXPORT_LIST
122438fd1498Szrj   /* Generate a list of directories from LIBPATH.  */
122538fd1498Szrj   prefix_from_env ("LIBPATH", &libpath_lib_dirs);
122638fd1498Szrj   /* Add to this list also two standard directories where
122738fd1498Szrj      AIX loader always searches for libraries.  */
122838fd1498Szrj   add_prefix (&libpath_lib_dirs, "/lib");
122938fd1498Szrj   add_prefix (&libpath_lib_dirs, "/usr/lib");
123038fd1498Szrj #endif
123138fd1498Szrj 
123238fd1498Szrj   /* Get any options that the upper GCC wants to pass to the sub-GCC.
123338fd1498Szrj 
123438fd1498Szrj      AIX support needs to know if -shared has been specified before
123538fd1498Szrj      parsing commandline arguments.  */
123638fd1498Szrj 
123738fd1498Szrj   p = getenv ("COLLECT_GCC_OPTIONS");
123838fd1498Szrj   while (p && *p)
123938fd1498Szrj     {
124038fd1498Szrj       const char *q = extract_string (&p);
124138fd1498Szrj       if (*q == '-' && (q[1] == 'm' || q[1] == 'f'))
124238fd1498Szrj 	*c_ptr++ = xstrdup (q);
124338fd1498Szrj       if (strcmp (q, "-EL") == 0 || strcmp (q, "-EB") == 0)
124438fd1498Szrj 	*c_ptr++ = xstrdup (q);
124538fd1498Szrj       if (strcmp (q, "-shared") == 0)
124638fd1498Szrj 	shared_obj = 1;
1247*58e805e6Szrj       if (strcmp (q, "-static") == 0)
1248*58e805e6Szrj 	static_obj = 1;
124938fd1498Szrj       if (*q == '-' && q[1] == 'B')
125038fd1498Szrj 	{
125138fd1498Szrj 	  *c_ptr++ = xstrdup (q);
125238fd1498Szrj 	  if (q[2] == 0)
125338fd1498Szrj 	    {
125438fd1498Szrj 	      q = extract_string (&p);
125538fd1498Szrj 	      *c_ptr++ = xstrdup (q);
125638fd1498Szrj 	    }
125738fd1498Szrj 	}
125838fd1498Szrj     }
125938fd1498Szrj   obstack_free (&temporary_obstack, temporary_firstobj);
126038fd1498Szrj   *c_ptr++ = "-fno-profile-arcs";
126138fd1498Szrj   *c_ptr++ = "-fno-test-coverage";
126238fd1498Szrj   *c_ptr++ = "-fno-branch-probabilities";
126338fd1498Szrj   *c_ptr++ = "-fno-exceptions";
126438fd1498Szrj   *c_ptr++ = "-w";
126538fd1498Szrj   *c_ptr++ = "-fno-whole-program";
126638fd1498Szrj 
126738fd1498Szrj   /* !!! When GCC calls collect2,
126838fd1498Szrj      it does not know whether it is calling collect2 or ld.
126938fd1498Szrj      So collect2 cannot meaningfully understand any options
127038fd1498Szrj      except those ld understands.
127138fd1498Szrj      If you propose to make GCC pass some other option,
127238fd1498Szrj      just imagine what will happen if ld is really ld!!!  */
127338fd1498Szrj 
127438fd1498Szrj   /* Parse arguments.  Remember output file spec, pass the rest to ld.  */
127538fd1498Szrj   /* After the first file, put in the c++ rt0.  */
127638fd1498Szrj 
1277*58e805e6Szrj #ifdef COLLECT_EXPORT_LIST
1278*58e805e6Szrj   is_static = static_obj;
1279*58e805e6Szrj #endif
128038fd1498Szrj   first_file = 1;
128138fd1498Szrj   while ((arg = *++argv) != (char *) 0)
128238fd1498Szrj     {
128338fd1498Szrj       *ld1++ = *ld2++ = arg;
128438fd1498Szrj 
128538fd1498Szrj       if (arg[0] == '-')
128638fd1498Szrj 	{
128738fd1498Szrj 	  switch (arg[1])
128838fd1498Szrj 	    {
128938fd1498Szrj 	    case 'd':
129038fd1498Szrj 	      if (!strcmp (arg, "-debug"))
129138fd1498Szrj 		{
129238fd1498Szrj 		  /* Already parsed.  */
129338fd1498Szrj 		  ld1--;
129438fd1498Szrj 		  ld2--;
129538fd1498Szrj 		}
129638fd1498Szrj 	      if (!strcmp (arg, "-dynamic-linker") && argv[1])
129738fd1498Szrj 		{
129838fd1498Szrj 		  ++argv;
129938fd1498Szrj 		  *ld1++ = *ld2++ = *argv;
130038fd1498Szrj 		}
130138fd1498Szrj 	      break;
130238fd1498Szrj 
130338fd1498Szrj             case 'f':
130438fd1498Szrj 	      if (strncmp (arg, "-flto", 5) == 0)
130538fd1498Szrj 		{
130638fd1498Szrj #ifdef ENABLE_LTO
130738fd1498Szrj 		  /* Do not pass LTO flag to the linker. */
130838fd1498Szrj 		  ld1--;
130938fd1498Szrj 		  ld2--;
131038fd1498Szrj #else
131138fd1498Szrj 		  error ("LTO support has not been enabled in this "
131238fd1498Szrj 			 "configuration");
131338fd1498Szrj #endif
131438fd1498Szrj 		}
131538fd1498Szrj 	      else if (!use_collect_ld
131638fd1498Szrj 		       && strncmp (arg, "-fuse-ld=", 9) == 0)
131738fd1498Szrj 		{
131838fd1498Szrj 		  /* Do not pass -fuse-ld={bfd|gold} to the linker. */
131938fd1498Szrj 		  ld1--;
132038fd1498Szrj 		  ld2--;
132138fd1498Szrj 		}
132238fd1498Szrj 	      else if (strncmp (arg, "-fno-lto", 8) == 0)
132338fd1498Szrj 		{
132438fd1498Szrj 		  /* Do not pass -fno-lto to the linker. */
132538fd1498Szrj 		  ld1--;
132638fd1498Szrj 		  ld2--;
132738fd1498Szrj 		}
132838fd1498Szrj #ifdef TARGET_AIX_VERSION
132938fd1498Szrj 	      else
133038fd1498Szrj 		{
133138fd1498Szrj 		  /* File containing a list of input files to process.  */
133238fd1498Szrj 
133338fd1498Szrj 		  FILE *stream;
133438fd1498Szrj                   char buf[MAXPATHLEN + 2];
133538fd1498Szrj 		  /* Number of additionnal object files.  */
133638fd1498Szrj 		  int add_nbr = 0;
133738fd1498Szrj 		  /* Maximum of additionnal object files before vector
133838fd1498Szrj 		     expansion.  */
133938fd1498Szrj 		  int add_max = 0;
134038fd1498Szrj 		  const char *list_filename = arg + 2;
134138fd1498Szrj 
134238fd1498Szrj 		  /* Accept -fFILENAME and -f FILENAME.  */
134338fd1498Szrj 		  if (*list_filename == '\0' && argv[1])
134438fd1498Szrj 		    {
134538fd1498Szrj 		      ++argv;
134638fd1498Szrj 		      list_filename = *argv;
134738fd1498Szrj 		      *ld1++ = *ld2++ = *argv;
134838fd1498Szrj 		    }
134938fd1498Szrj 
135038fd1498Szrj 		  stream = fopen (list_filename, "r");
135138fd1498Szrj 		  if (stream == NULL)
135238fd1498Szrj 		    fatal_error (input_location, "can't open %s: %m",
135338fd1498Szrj 				 list_filename);
135438fd1498Szrj 
135538fd1498Szrj 		  while (fgets (buf, sizeof buf, stream) != NULL)
135638fd1498Szrj 		    {
135738fd1498Szrj 		      /* Remove end of line.  */
135838fd1498Szrj 		      int len = strlen (buf);
135938fd1498Szrj 		      if (len >= 1 && buf[len - 1] =='\n')
136038fd1498Szrj 			buf[len - 1] = '\0';
136138fd1498Szrj 
136238fd1498Szrj 		      /* Put on object vector.
136338fd1498Szrj 			 Note: we only expanse vector here, so we must keep
136438fd1498Szrj 			 extra space for remaining arguments.  */
136538fd1498Szrj 		      if (add_nbr >= add_max)
136638fd1498Szrj 			{
136738fd1498Szrj 			  int pos =
136838fd1498Szrj 			    object - CONST_CAST2 (const char **, char **,
136938fd1498Szrj 						  object_lst);
137038fd1498Szrj 			  add_max = (add_max == 0) ? 16 : add_max * 2;
137138fd1498Szrj 			  object_lst = XRESIZEVEC (char *, object_lst,
137238fd1498Szrj                                                    object_nbr + add_max);
137338fd1498Szrj 			  object = CONST_CAST2 (const char **, char **,
137438fd1498Szrj 						object_lst) + pos;
137538fd1498Szrj 			  object_nbr += add_max;
137638fd1498Szrj 			}
137738fd1498Szrj 		      *object++ = xstrdup (buf);
137838fd1498Szrj 		      add_nbr++;
137938fd1498Szrj 		    }
138038fd1498Szrj 		  fclose (stream);
138138fd1498Szrj 		}
138238fd1498Szrj #endif
138338fd1498Szrj               break;
138438fd1498Szrj 
1385*58e805e6Szrj #ifdef COLLECT_EXPORT_LIST
1386*58e805e6Szrj 	    case 'b':
1387*58e805e6Szrj 	      if (!strcmp (arg, "-bstatic"))
1388*58e805e6Szrj 		{
1389*58e805e6Szrj 		  is_static = true;
1390*58e805e6Szrj 		}
1391*58e805e6Szrj 	      else if (!strcmp (arg, "-bdynamic") || !strcmp (arg, "-bshared"))
1392*58e805e6Szrj 		{
1393*58e805e6Szrj 		  is_static = false;
1394*58e805e6Szrj 		}
1395*58e805e6Szrj 	      break;
1396*58e805e6Szrj #endif
139738fd1498Szrj 	    case 'l':
139838fd1498Szrj 	      if (first_file)
139938fd1498Szrj 		{
140038fd1498Szrj 		  /* place o_file BEFORE this argument! */
140138fd1498Szrj 		  first_file = 0;
140238fd1498Szrj 		  ld2--;
140338fd1498Szrj 		  *ld2++ = o_file;
140438fd1498Szrj 		  *ld2++ = arg;
140538fd1498Szrj 		}
140638fd1498Szrj #ifdef COLLECT_EXPORT_LIST
140738fd1498Szrj 	      {
140838fd1498Szrj 		/* Resolving full library name.  */
140938fd1498Szrj 		const char *s = resolve_lib_name (arg+2);
141038fd1498Szrj 
141138fd1498Szrj 		/* Saving a full library name.  */
141238fd1498Szrj 		add_to_list (&libs, s);
1413*58e805e6Szrj 		if (is_static)
1414*58e805e6Szrj 		    add_to_list (&static_libs, s);
141538fd1498Szrj 	      }
141638fd1498Szrj #endif
141738fd1498Szrj 	      break;
141838fd1498Szrj 
141938fd1498Szrj #ifdef COLLECT_EXPORT_LIST
142038fd1498Szrj 	    /* Saving directories where to search for libraries.  */
142138fd1498Szrj 	    case 'L':
142238fd1498Szrj 	      add_prefix (&cmdline_lib_dirs, arg+2);
142338fd1498Szrj 	      break;
142438fd1498Szrj #endif
142538fd1498Szrj 
142638fd1498Szrj 	    case 'o':
142738fd1498Szrj 	      if (arg[2] == '\0')
142838fd1498Szrj 		output_file = *ld1++ = *ld2++ = *++argv;
142938fd1498Szrj 	      else
143038fd1498Szrj 		output_file = &arg[2];
143138fd1498Szrj 	      break;
143238fd1498Szrj 
143338fd1498Szrj 	    case 'r':
143438fd1498Szrj 	      if (arg[2] == '\0')
143538fd1498Szrj 		rflag = 1;
143638fd1498Szrj 	      break;
143738fd1498Szrj 
143838fd1498Szrj 	    case 's':
143938fd1498Szrj 	      if (arg[2] == '\0' && do_collecting)
144038fd1498Szrj 		{
144138fd1498Szrj 		  /* We must strip after the nm run, otherwise C++ linking
144238fd1498Szrj 		     will not work.  Thus we strip in the second ld run, or
144338fd1498Szrj 		     else with strip if there is no second ld run.  */
144438fd1498Szrj 		  strip_flag = 1;
144538fd1498Szrj 		  ld1--;
144638fd1498Szrj 		}
144738fd1498Szrj 	      break;
144838fd1498Szrj 
144938fd1498Szrj 	    case 'v':
145038fd1498Szrj 	      if (arg[2] == '\0')
145138fd1498Szrj 		verbose = true;
145238fd1498Szrj 	      break;
145338fd1498Szrj 
145438fd1498Szrj 	    case '-':
145538fd1498Szrj 	      if (strcmp (arg, "--no-demangle") == 0)
145638fd1498Szrj 		{
145738fd1498Szrj #ifndef HAVE_LD_DEMANGLE
145838fd1498Szrj 		  no_demangle = 1;
145938fd1498Szrj 		  ld1--;
146038fd1498Szrj 		  ld2--;
146138fd1498Szrj #endif
146238fd1498Szrj 		}
146338fd1498Szrj 	      else if (strncmp (arg, "--demangle", 10) == 0)
146438fd1498Szrj 		{
146538fd1498Szrj #ifndef HAVE_LD_DEMANGLE
146638fd1498Szrj 		  no_demangle = 0;
146738fd1498Szrj 		  if (arg[10] == '=')
146838fd1498Szrj 		    {
146938fd1498Szrj 		      enum demangling_styles style
147038fd1498Szrj 			= cplus_demangle_name_to_style (arg+11);
147138fd1498Szrj 		      if (style == unknown_demangling)
147238fd1498Szrj 			error ("unknown demangling style '%s'", arg+11);
147338fd1498Szrj 		      else
147438fd1498Szrj 			current_demangling_style = style;
147538fd1498Szrj 		    }
147638fd1498Szrj 		  ld1--;
147738fd1498Szrj 		  ld2--;
147838fd1498Szrj #endif
147938fd1498Szrj 		}
148038fd1498Szrj 	      else if (strncmp (arg, "--sysroot=", 10) == 0)
148138fd1498Szrj 		target_system_root = arg + 10;
148238fd1498Szrj 	      else if (strcmp (arg, "--version") == 0)
148338fd1498Szrj 		verbose = true;
148438fd1498Szrj 	      else if (strcmp (arg, "--help") == 0)
148538fd1498Szrj 		helpflag = true;
148638fd1498Szrj 	      break;
148738fd1498Szrj 	    }
148838fd1498Szrj 	}
148938fd1498Szrj       else if ((p = strrchr (arg, '.')) != (char *) 0
149038fd1498Szrj 	       && (strcmp (p, ".o") == 0 || strcmp (p, ".a") == 0
149138fd1498Szrj 		   || strcmp (p, ".so") == 0 || strcmp (p, ".lo") == 0
149238fd1498Szrj 		   || strcmp (p, ".obj") == 0))
149338fd1498Szrj 	{
149438fd1498Szrj 	  if (first_file)
149538fd1498Szrj 	    {
149638fd1498Szrj 	      first_file = 0;
149738fd1498Szrj 	      if (p[1] == 'o')
149838fd1498Szrj 		*ld2++ = o_file;
149938fd1498Szrj 	      else
150038fd1498Szrj 		{
150138fd1498Szrj 		  /* place o_file BEFORE this argument! */
150238fd1498Szrj 		  ld2--;
150338fd1498Szrj 		  *ld2++ = o_file;
150438fd1498Szrj 		  *ld2++ = arg;
150538fd1498Szrj 		}
150638fd1498Szrj 	    }
150738fd1498Szrj 	  if (p[1] == 'o' || p[1] == 'l')
150838fd1498Szrj 	    *object++ = arg;
150938fd1498Szrj #ifdef COLLECT_EXPORT_LIST
151038fd1498Szrj 	  /* libraries can be specified directly, i.e. without -l flag.  */
151138fd1498Szrj 	  else
151238fd1498Szrj 	    {
151338fd1498Szrj 	      /* Saving a full library name.  */
151438fd1498Szrj 	      add_to_list (&libs, arg);
1515*58e805e6Szrj 	      if (is_static)
1516*58e805e6Szrj 		add_to_list (&static_libs, arg);
151738fd1498Szrj 	    }
151838fd1498Szrj #endif
151938fd1498Szrj 	}
152038fd1498Szrj     }
152138fd1498Szrj 
152238fd1498Szrj #ifdef COLLECT_EXPORT_LIST
152338fd1498Szrj   /* This is added only for debugging purposes.  */
152438fd1498Szrj   if (debug)
152538fd1498Szrj     {
152638fd1498Szrj       fprintf (stderr, "List of libraries:\n");
152738fd1498Szrj       dump_list (stderr, "\t", libs.first);
1528*58e805e6Szrj       fprintf (stderr, "List of statically linked libraries:\n");
1529*58e805e6Szrj       dump_list (stderr, "\t", static_libs.first);
153038fd1498Szrj     }
153138fd1498Szrj 
153238fd1498Szrj   /* The AIX linker will discard static constructors in object files if
153338fd1498Szrj      nothing else in the file is referenced, so look at them first.  Unless
153438fd1498Szrj      we are building a shared object, ignore the eh frame tables, as we
153538fd1498Szrj      would otherwise reference them all, hence drag all the corresponding
153638fd1498Szrj      objects even if nothing else is referenced.  */
153738fd1498Szrj   {
153838fd1498Szrj     const char **export_object_lst
153938fd1498Szrj       = CONST_CAST2 (const char **, char **, object_lst);
154038fd1498Szrj 
154138fd1498Szrj     struct id *list = libs.first;
154238fd1498Szrj 
154338fd1498Szrj     /* Compute the filter to use from the current one, do scan, then adjust
154438fd1498Szrj        the "current" filter to remove what we just included here.  This will
154538fd1498Szrj        control whether we need a first pass link later on or not, and what
154638fd1498Szrj        will remain to be scanned there.  */
154738fd1498Szrj 
154838fd1498Szrj     scanfilter this_filter = ld1_filter;
154938fd1498Szrj #if HAVE_AS_REF
155038fd1498Szrj     if (!shared_obj)
155138fd1498Szrj       this_filter &= ~SCAN_DWEH;
155238fd1498Szrj #endif
155338fd1498Szrj 
1554*58e805e6Szrj     /* Scan object files.  */
155538fd1498Szrj     while (export_object_lst < object)
155638fd1498Szrj       scan_prog_file (*export_object_lst++, PASS_OBJ, this_filter);
155738fd1498Szrj 
1558*58e805e6Szrj     /* Scan libraries.  */
155938fd1498Szrj     for (; list; list = list->next)
156038fd1498Szrj       scan_prog_file (list->name, PASS_FIRST, this_filter);
156138fd1498Szrj 
156238fd1498Szrj     ld1_filter = ld1_filter & ~this_filter;
156338fd1498Szrj   }
156438fd1498Szrj 
156538fd1498Szrj   if (exports.first)
156638fd1498Szrj     {
156738fd1498Szrj       char *buf = concat ("-bE:", export_file, NULL);
156838fd1498Szrj 
156938fd1498Szrj       *ld1++ = buf;
157038fd1498Szrj       *ld2++ = buf;
157138fd1498Szrj 
157238fd1498Szrj       exportf = fopen (export_file, "w");
157338fd1498Szrj       if (exportf == (FILE *) 0)
157438fd1498Szrj 	fatal_error (input_location, "fopen %s: %m", export_file);
157538fd1498Szrj       write_aix_file (exportf, exports.first);
157638fd1498Szrj       if (fclose (exportf))
157738fd1498Szrj 	fatal_error (input_location, "fclose %s: %m", export_file);
157838fd1498Szrj     }
157938fd1498Szrj #endif
158038fd1498Szrj 
158138fd1498Szrj   *c_ptr++ = c_file;
158238fd1498Szrj   *c_ptr = *ld1 = *object = (char *) 0;
158338fd1498Szrj 
158438fd1498Szrj   if (verbose)
158538fd1498Szrj     notice ("collect2 version %s\n", version_string);
158638fd1498Szrj 
158738fd1498Szrj   if (helpflag)
158838fd1498Szrj     {
158938fd1498Szrj       printf ("Usage: collect2 [options]\n");
159038fd1498Szrj       printf (" Wrap linker and generate constructor code if needed.\n");
159138fd1498Szrj       printf (" Options:\n");
159238fd1498Szrj       printf ("  -debug          Enable debug output\n");
159338fd1498Szrj       printf ("  --help          Display this information\n");
159438fd1498Szrj       printf ("  -v, --version   Display this program's version number\n");
159538fd1498Szrj       printf ("\n");
159638fd1498Szrj       printf ("Overview: http://gcc.gnu.org/onlinedocs/gccint/Collect2.html\n");
159738fd1498Szrj       printf ("Report bugs: %s\n", bug_report_url);
159838fd1498Szrj       printf ("\n");
159938fd1498Szrj     }
160038fd1498Szrj 
160138fd1498Szrj   if (debug)
160238fd1498Szrj     {
160338fd1498Szrj       const char *ptr;
160438fd1498Szrj       fprintf (stderr, "ld_file_name        = %s\n",
160538fd1498Szrj 	       (ld_file_name ? ld_file_name : "not found"));
160638fd1498Szrj       fprintf (stderr, "c_file_name         = %s\n",
160738fd1498Szrj 	       (c_file_name ? c_file_name : "not found"));
160838fd1498Szrj       fprintf (stderr, "nm_file_name        = %s\n",
160938fd1498Szrj 	       (nm_file_name ? nm_file_name : "not found"));
161038fd1498Szrj #ifdef LDD_SUFFIX
161138fd1498Szrj       fprintf (stderr, "ldd_file_name       = %s\n",
161238fd1498Szrj 	       (ldd_file_name ? ldd_file_name : "not found"));
161338fd1498Szrj #endif
161438fd1498Szrj       fprintf (stderr, "strip_file_name     = %s\n",
161538fd1498Szrj 	       (strip_file_name ? strip_file_name : "not found"));
161638fd1498Szrj       fprintf (stderr, "c_file              = %s\n",
161738fd1498Szrj 	       (c_file ? c_file : "not found"));
161838fd1498Szrj       fprintf (stderr, "o_file              = %s\n",
161938fd1498Szrj 	       (o_file ? o_file : "not found"));
162038fd1498Szrj 
162138fd1498Szrj       ptr = getenv ("COLLECT_GCC_OPTIONS");
162238fd1498Szrj       if (ptr)
162338fd1498Szrj 	fprintf (stderr, "COLLECT_GCC_OPTIONS = %s\n", ptr);
162438fd1498Szrj 
162538fd1498Szrj       ptr = getenv ("COLLECT_GCC");
162638fd1498Szrj       if (ptr)
162738fd1498Szrj 	fprintf (stderr, "COLLECT_GCC         = %s\n", ptr);
162838fd1498Szrj 
162938fd1498Szrj       ptr = getenv ("COMPILER_PATH");
163038fd1498Szrj       if (ptr)
163138fd1498Szrj 	fprintf (stderr, "COMPILER_PATH       = %s\n", ptr);
163238fd1498Szrj 
163338fd1498Szrj       ptr = getenv (LIBRARY_PATH_ENV);
163438fd1498Szrj       if (ptr)
163538fd1498Szrj 	fprintf (stderr, "%-20s= %s\n", LIBRARY_PATH_ENV, ptr);
163638fd1498Szrj 
163738fd1498Szrj       fprintf (stderr, "\n");
163838fd1498Szrj     }
163938fd1498Szrj 
164038fd1498Szrj   /* Load the program, searching all libraries and attempting to provide
164138fd1498Szrj      undefined symbols from repository information.
164238fd1498Szrj 
164338fd1498Szrj      If -r or they will be run via some other method, do not build the
164438fd1498Szrj      constructor or destructor list, just return now.  */
164538fd1498Szrj   {
164638fd1498Szrj     bool early_exit
164738fd1498Szrj       = rflag || (! DO_COLLECT_EXPORT_LIST && ! do_collecting);
164838fd1498Szrj 
164938fd1498Szrj     /* Perform the first pass link now, if we're about to exit or if we need
165038fd1498Szrj        to scan for things we haven't collected yet before pursuing further.
165138fd1498Szrj 
165238fd1498Szrj        On AIX, the latter typically includes nothing for shared objects or
165338fd1498Szrj        frame tables for an executable, out of what the required early scan on
165438fd1498Szrj        objects and libraries has performed above.  In the !shared_obj case, we
165538fd1498Szrj        expect the relevant tables to be dragged together with their associated
165638fd1498Szrj        functions from precise cross reference insertions by the compiler.  */
165738fd1498Szrj 
165838fd1498Szrj     if (early_exit || ld1_filter != SCAN_NOTHING)
165938fd1498Szrj       do_tlink (ld1_argv, object_lst);
166038fd1498Szrj 
166138fd1498Szrj     if (early_exit)
166238fd1498Szrj       {
166338fd1498Szrj #ifdef COLLECT_EXPORT_LIST
166438fd1498Szrj 	/* Make sure we delete the export file we may have created.  */
166538fd1498Szrj 	if (export_file != 0 && export_file[0])
166638fd1498Szrj 	  maybe_unlink (export_file);
166738fd1498Szrj #endif
166838fd1498Szrj 	if (lto_mode != LTO_MODE_NONE)
166938fd1498Szrj 	  maybe_run_lto_and_relink (ld1_argv, object_lst, object, false);
167038fd1498Szrj 	else
167138fd1498Szrj 	  post_ld_pass (false);
167238fd1498Szrj 
167338fd1498Szrj 	maybe_unlink (c_file);
167438fd1498Szrj 	maybe_unlink (o_file);
167538fd1498Szrj 	return 0;
167638fd1498Szrj       }
167738fd1498Szrj   }
167838fd1498Szrj 
167938fd1498Szrj   /* Unless we have done it all already, examine the namelist and search for
168038fd1498Szrj      static constructors and destructors to call.  Write the constructor and
168138fd1498Szrj      destructor tables to a .s file and reload.  */
168238fd1498Szrj 
168338fd1498Szrj   if (ld1_filter != SCAN_NOTHING)
168438fd1498Szrj     scan_prog_file (output_file, PASS_FIRST, ld1_filter);
168538fd1498Szrj 
168638fd1498Szrj #ifdef SCAN_LIBRARIES
168738fd1498Szrj   scan_libraries (output_file);
168838fd1498Szrj #endif
168938fd1498Szrj 
169038fd1498Szrj   if (debug)
169138fd1498Szrj     {
169238fd1498Szrj       notice_translated (ngettext ("%d constructor found\n",
169338fd1498Szrj                                    "%d constructors found\n",
169438fd1498Szrj                                    constructors.number),
169538fd1498Szrj                          constructors.number);
169638fd1498Szrj       notice_translated (ngettext ("%d destructor found\n",
169738fd1498Szrj                                    "%d destructors found\n",
169838fd1498Szrj                                    destructors.number),
169938fd1498Szrj                          destructors.number);
170038fd1498Szrj       notice_translated (ngettext ("%d frame table found\n",
170138fd1498Szrj                                    "%d frame tables found\n",
170238fd1498Szrj 				   frame_tables.number),
170338fd1498Szrj                          frame_tables.number);
170438fd1498Szrj     }
170538fd1498Szrj 
170638fd1498Szrj   /* If the scan exposed nothing of special interest, there's no need to
170738fd1498Szrj      generate the glue code and relink so return now.  */
170838fd1498Szrj 
170938fd1498Szrj   if (constructors.number == 0 && destructors.number == 0
171038fd1498Szrj       && frame_tables.number == 0
171138fd1498Szrj #if defined (SCAN_LIBRARIES) || defined (COLLECT_EXPORT_LIST)
171238fd1498Szrj       /* If we will be running these functions ourselves, we want to emit
171338fd1498Szrj 	 stubs into the shared library so that we do not have to relink
171438fd1498Szrj 	 dependent programs when we add static objects.  */
171538fd1498Szrj       && ! shared_obj
171638fd1498Szrj #endif
171738fd1498Szrj       )
171838fd1498Szrj     {
171938fd1498Szrj       /* Do tlink without additional code generation now if we didn't
172038fd1498Szrj 	 do it earlier for scanning purposes.  */
172138fd1498Szrj       if (ld1_filter == SCAN_NOTHING)
172238fd1498Szrj 	do_tlink (ld1_argv, object_lst);
172338fd1498Szrj 
172438fd1498Szrj       if (lto_mode)
172538fd1498Szrj         maybe_run_lto_and_relink (ld1_argv, object_lst, object, false);
172638fd1498Szrj 
172738fd1498Szrj       /* Strip now if it was requested on the command line.  */
172838fd1498Szrj       if (strip_flag)
172938fd1498Szrj 	{
173038fd1498Szrj 	  char **real_strip_argv = XCNEWVEC (char *, 3);
173138fd1498Szrj 	  const char ** strip_argv = CONST_CAST2 (const char **, char **,
173238fd1498Szrj 						  real_strip_argv);
173338fd1498Szrj 
173438fd1498Szrj 	  strip_argv[0] = strip_file_name;
173538fd1498Szrj 	  strip_argv[1] = output_file;
173638fd1498Szrj 	  strip_argv[2] = (char *) 0;
173738fd1498Szrj 	  fork_execute ("strip", real_strip_argv, false);
173838fd1498Szrj 	}
173938fd1498Szrj 
174038fd1498Szrj #ifdef COLLECT_EXPORT_LIST
174138fd1498Szrj       maybe_unlink (export_file);
174238fd1498Szrj #endif
174338fd1498Szrj       post_ld_pass (false);
174438fd1498Szrj 
174538fd1498Szrj       maybe_unlink (c_file);
174638fd1498Szrj       maybe_unlink (o_file);
174738fd1498Szrj       return 0;
174838fd1498Szrj     }
174938fd1498Szrj 
175038fd1498Szrj   /* Sort ctor and dtor lists by priority.  */
175138fd1498Szrj   sort_ids (&constructors);
175238fd1498Szrj   sort_ids (&destructors);
175338fd1498Szrj 
175438fd1498Szrj   maybe_unlink (output_file);
175538fd1498Szrj   outf = fopen (c_file, "w");
175638fd1498Szrj   if (outf == (FILE *) 0)
175738fd1498Szrj     fatal_error (input_location, "fopen %s: %m", c_file);
175838fd1498Szrj 
175938fd1498Szrj   write_c_file (outf, c_file);
176038fd1498Szrj 
176138fd1498Szrj   if (fclose (outf))
176238fd1498Szrj     fatal_error (input_location, "fclose %s: %m", c_file);
176338fd1498Szrj 
176438fd1498Szrj   /* Tell the linker that we have initializer and finalizer functions.  */
176538fd1498Szrj #ifdef LD_INIT_SWITCH
176638fd1498Szrj #ifdef COLLECT_EXPORT_LIST
176738fd1498Szrj   *ld2++ = concat (LD_INIT_SWITCH, ":", initname, ":", fininame, NULL);
176838fd1498Szrj #else
176938fd1498Szrj   *ld2++ = LD_INIT_SWITCH;
177038fd1498Szrj   *ld2++ = initname;
177138fd1498Szrj   *ld2++ = LD_FINI_SWITCH;
177238fd1498Szrj   *ld2++ = fininame;
177338fd1498Szrj #endif
177438fd1498Szrj #endif
177538fd1498Szrj 
177638fd1498Szrj #ifdef COLLECT_EXPORT_LIST
177738fd1498Szrj   if (shared_obj)
177838fd1498Szrj     {
177938fd1498Szrj       /* If we did not add export flag to link arguments before, add it to
178038fd1498Szrj 	 second link phase now.  No new exports should have been added.  */
178138fd1498Szrj       if (! exports.first)
178238fd1498Szrj 	*ld2++ = concat ("-bE:", export_file, NULL);
178338fd1498Szrj 
178438fd1498Szrj #ifdef TARGET_AIX_VERSION
178538fd1498Szrj       add_to_list (&exports, aix_shared_initname);
178638fd1498Szrj       add_to_list (&exports, aix_shared_fininame);
178738fd1498Szrj #endif
178838fd1498Szrj 
178938fd1498Szrj #ifndef LD_INIT_SWITCH
179038fd1498Szrj       add_to_list (&exports, initname);
179138fd1498Szrj       add_to_list (&exports, fininame);
179238fd1498Szrj       add_to_list (&exports, "_GLOBAL__DI");
179338fd1498Szrj       add_to_list (&exports, "_GLOBAL__DD");
179438fd1498Szrj #endif
179538fd1498Szrj       exportf = fopen (export_file, "w");
179638fd1498Szrj       if (exportf == (FILE *) 0)
179738fd1498Szrj 	fatal_error (input_location, "fopen %s: %m", export_file);
179838fd1498Szrj       write_aix_file (exportf, exports.first);
179938fd1498Szrj       if (fclose (exportf))
180038fd1498Szrj 	fatal_error (input_location, "fclose %s: %m", export_file);
180138fd1498Szrj     }
180238fd1498Szrj #endif
180338fd1498Szrj 
180438fd1498Szrj   /* End of arguments to second link phase.  */
180538fd1498Szrj   *ld2 = (char*) 0;
180638fd1498Szrj 
180738fd1498Szrj   if (debug)
180838fd1498Szrj     {
180938fd1498Szrj       fprintf (stderr, "\n========== output_file = %s, c_file = %s\n",
181038fd1498Szrj 	       output_file, c_file);
181138fd1498Szrj       write_c_file (stderr, "stderr");
181238fd1498Szrj       fprintf (stderr, "========== end of c_file\n\n");
181338fd1498Szrj #ifdef COLLECT_EXPORT_LIST
181438fd1498Szrj       fprintf (stderr, "\n========== export_file = %s\n", export_file);
181538fd1498Szrj       write_aix_file (stderr, exports.first);
181638fd1498Szrj       fprintf (stderr, "========== end of export_file\n\n");
181738fd1498Szrj #endif
181838fd1498Szrj     }
181938fd1498Szrj 
182038fd1498Szrj   /* Assemble the constructor and destructor tables.
182138fd1498Szrj      Link the tables in with the rest of the program.  */
182238fd1498Szrj 
182338fd1498Szrj   fork_execute ("gcc",  c_argv, at_file_supplied);
182438fd1498Szrj #ifdef COLLECT_EXPORT_LIST
182538fd1498Szrj   /* On AIX we must call tlink because of possible templates resolution.  */
182638fd1498Szrj   do_tlink (ld2_argv, object_lst);
182738fd1498Szrj 
182838fd1498Szrj   if (lto_mode)
182938fd1498Szrj     maybe_run_lto_and_relink (ld2_argv, object_lst, object, false);
183038fd1498Szrj #else
183138fd1498Szrj   /* Otherwise, simply call ld because tlink is already done.  */
183238fd1498Szrj   if (lto_mode)
183338fd1498Szrj     maybe_run_lto_and_relink (ld2_argv, object_lst, object, true);
183438fd1498Szrj   else
183538fd1498Szrj     {
183638fd1498Szrj       fork_execute ("ld", ld2_argv, HAVE_GNU_LD && at_file_supplied);
183738fd1498Szrj       post_ld_pass (false);
183838fd1498Szrj     }
183938fd1498Szrj 
184038fd1498Szrj   /* Let scan_prog_file do any final mods (OSF/rose needs this for
184138fd1498Szrj      constructors/destructors in shared libraries.  */
184238fd1498Szrj   scan_prog_file (output_file, PASS_SECOND, SCAN_ALL);
184338fd1498Szrj #endif
184438fd1498Szrj 
184538fd1498Szrj   maybe_unlink (c_file);
184638fd1498Szrj   maybe_unlink (o_file);
184738fd1498Szrj 
184838fd1498Szrj #ifdef COLLECT_EXPORT_LIST
184938fd1498Szrj   maybe_unlink (export_file);
185038fd1498Szrj #endif
185138fd1498Szrj 
185238fd1498Szrj   return 0;
185338fd1498Szrj }
185438fd1498Szrj 
185538fd1498Szrj 
185638fd1498Szrj /* Unlink FILE unless we are debugging or this is the output_file
185738fd1498Szrj    and we may not unlink it.  */
185838fd1498Szrj 
185938fd1498Szrj void
maybe_unlink(const char * file)186038fd1498Szrj maybe_unlink (const char *file)
186138fd1498Szrj {
186238fd1498Szrj   if (debug)
186338fd1498Szrj     {
186438fd1498Szrj       notice ("[Leaving %s]\n", file);
186538fd1498Szrj       return;
186638fd1498Szrj     }
186738fd1498Szrj 
186838fd1498Szrj   if (file == output_file && !may_unlink_output_file)
186938fd1498Szrj     return;
187038fd1498Szrj 
187138fd1498Szrj   unlink_if_ordinary (file);
187238fd1498Szrj }
187338fd1498Szrj 
187438fd1498Szrj /* Call maybe_unlink on the NULL-terminated list, FILE_LIST.  */
187538fd1498Szrj 
187638fd1498Szrj static void
maybe_unlink_list(char ** file_list)187738fd1498Szrj maybe_unlink_list (char **file_list)
187838fd1498Szrj {
187938fd1498Szrj   char **tmp = file_list;
188038fd1498Szrj 
188138fd1498Szrj   while (*tmp)
188238fd1498Szrj     maybe_unlink (*(tmp++));
188338fd1498Szrj }
188438fd1498Szrj 
188538fd1498Szrj 
188638fd1498Szrj static long sequence_number = 0;
188738fd1498Szrj 
188838fd1498Szrj /* Add a name to a linked list.  */
188938fd1498Szrj 
189038fd1498Szrj static void
add_to_list(struct head * head_ptr,const char * name)189138fd1498Szrj add_to_list (struct head *head_ptr, const char *name)
189238fd1498Szrj {
189338fd1498Szrj   struct id *newid
189438fd1498Szrj     = (struct id *) xcalloc (sizeof (struct id) + strlen (name), 1);
189538fd1498Szrj   struct id *p;
189638fd1498Szrj   strcpy (newid->name, name);
189738fd1498Szrj 
189838fd1498Szrj   if (head_ptr->first)
189938fd1498Szrj     head_ptr->last->next = newid;
190038fd1498Szrj   else
190138fd1498Szrj     head_ptr->first = newid;
190238fd1498Szrj 
190338fd1498Szrj   /* Check for duplicate symbols.  */
190438fd1498Szrj   for (p = head_ptr->first;
190538fd1498Szrj        strcmp (name, p->name) != 0;
190638fd1498Szrj        p = p->next)
190738fd1498Szrj     ;
190838fd1498Szrj   if (p != newid)
190938fd1498Szrj     {
191038fd1498Szrj       head_ptr->last->next = 0;
191138fd1498Szrj       free (newid);
191238fd1498Szrj       return;
191338fd1498Szrj     }
191438fd1498Szrj 
191538fd1498Szrj   newid->sequence = ++sequence_number;
191638fd1498Szrj   head_ptr->last = newid;
191738fd1498Szrj   head_ptr->number++;
191838fd1498Szrj }
191938fd1498Szrj 
192038fd1498Szrj /* Grab the init priority number from an init function name that
192138fd1498Szrj    looks like "_GLOBAL_.I.12345.foo".  */
192238fd1498Szrj 
192338fd1498Szrj static int
extract_init_priority(const char * name)192438fd1498Szrj extract_init_priority (const char *name)
192538fd1498Szrj {
192638fd1498Szrj   int pos = 0, pri;
192738fd1498Szrj 
192838fd1498Szrj #ifdef TARGET_AIX_VERSION
192938fd1498Szrj   /* Run dependent module initializers before any constructors in this
193038fd1498Szrj      module.  */
193138fd1498Szrj   switch (is_ctor_dtor (name))
193238fd1498Szrj     {
193338fd1498Szrj     case SYM_AIXI:
193438fd1498Szrj     case SYM_AIXD:
193538fd1498Szrj       return INT_MIN;
193638fd1498Szrj     default:
193738fd1498Szrj       break;
193838fd1498Szrj     }
193938fd1498Szrj #endif
194038fd1498Szrj 
194138fd1498Szrj   while (name[pos] == '_')
194238fd1498Szrj     ++pos;
194338fd1498Szrj   pos += 10; /* strlen ("GLOBAL__X_") */
194438fd1498Szrj 
194538fd1498Szrj   /* Extract init_p number from ctor/dtor name.  */
194638fd1498Szrj   pri = atoi (name + pos);
194738fd1498Szrj   return pri ? pri : DEFAULT_INIT_PRIORITY;
194838fd1498Szrj }
194938fd1498Szrj 
195038fd1498Szrj /* Insertion sort the ids from ctor/dtor list HEAD_PTR in descending order.
195138fd1498Szrj    ctors will be run from right to left, dtors from left to right.  */
195238fd1498Szrj 
195338fd1498Szrj static void
sort_ids(struct head * head_ptr)195438fd1498Szrj sort_ids (struct head *head_ptr)
195538fd1498Szrj {
195638fd1498Szrj   /* id holds the current element to insert.  id_next holds the next
195738fd1498Szrj      element to insert.  id_ptr iterates through the already sorted elements
195838fd1498Szrj      looking for the place to insert id.  */
195938fd1498Szrj   struct id *id, *id_next, **id_ptr;
196038fd1498Szrj 
196138fd1498Szrj   id = head_ptr->first;
196238fd1498Szrj 
196338fd1498Szrj   /* We don't have any sorted elements yet.  */
196438fd1498Szrj   head_ptr->first = NULL;
196538fd1498Szrj 
196638fd1498Szrj   for (; id; id = id_next)
196738fd1498Szrj     {
196838fd1498Szrj       id_next = id->next;
196938fd1498Szrj       id->sequence = extract_init_priority (id->name);
197038fd1498Szrj 
197138fd1498Szrj       for (id_ptr = &(head_ptr->first); ; id_ptr = &((*id_ptr)->next))
197238fd1498Szrj 	if (*id_ptr == NULL
197338fd1498Szrj 	    /* If the sequence numbers are the same, we put the id from the
197438fd1498Szrj 	       file later on the command line later in the list.  */
197538fd1498Szrj 	    || id->sequence > (*id_ptr)->sequence
197638fd1498Szrj 	    /* Hack: do lexical compare, too.
197738fd1498Szrj 	    || (id->sequence == (*id_ptr)->sequence
197838fd1498Szrj 		&& strcmp (id->name, (*id_ptr)->name) > 0) */
197938fd1498Szrj 	    )
198038fd1498Szrj 	  {
198138fd1498Szrj 	    id->next = *id_ptr;
198238fd1498Szrj 	    *id_ptr = id;
198338fd1498Szrj 	    break;
198438fd1498Szrj 	  }
198538fd1498Szrj     }
198638fd1498Szrj 
198738fd1498Szrj   /* Now set the sequence numbers properly so write_c_file works.  */
198838fd1498Szrj   for (id = head_ptr->first; id; id = id->next)
198938fd1498Szrj     id->sequence = ++sequence_number;
199038fd1498Szrj }
199138fd1498Szrj 
199238fd1498Szrj /* Write: `prefix', the names on list LIST, `suffix'.  */
199338fd1498Szrj 
199438fd1498Szrj static void
write_list(FILE * stream,const char * prefix,struct id * list)199538fd1498Szrj write_list (FILE *stream, const char *prefix, struct id *list)
199638fd1498Szrj {
199738fd1498Szrj   while (list)
199838fd1498Szrj     {
199938fd1498Szrj       fprintf (stream, "%sx%d,\n", prefix, list->sequence);
200038fd1498Szrj       list = list->next;
200138fd1498Szrj     }
200238fd1498Szrj }
200338fd1498Szrj 
200438fd1498Szrj #ifdef COLLECT_EXPORT_LIST
200538fd1498Szrj /* This function is really used only on AIX, but may be useful.  */
200638fd1498Szrj static int
is_in_list(const char * prefix,struct id * list)200738fd1498Szrj is_in_list (const char *prefix, struct id *list)
200838fd1498Szrj {
200938fd1498Szrj   while (list)
201038fd1498Szrj     {
201138fd1498Szrj       if (!strcmp (prefix, list->name)) return 1;
201238fd1498Szrj       list = list->next;
201338fd1498Szrj     }
201438fd1498Szrj     return 0;
201538fd1498Szrj }
201638fd1498Szrj #endif /* COLLECT_EXPORT_LIST */
201738fd1498Szrj 
201838fd1498Szrj /* Added for debugging purpose.  */
201938fd1498Szrj #ifdef COLLECT_EXPORT_LIST
202038fd1498Szrj static void
dump_list(FILE * stream,const char * prefix,struct id * list)202138fd1498Szrj dump_list (FILE *stream, const char *prefix, struct id *list)
202238fd1498Szrj {
202338fd1498Szrj   while (list)
202438fd1498Szrj     {
202538fd1498Szrj       fprintf (stream, "%s%s,\n", prefix, list->name);
202638fd1498Szrj       list = list->next;
202738fd1498Szrj     }
202838fd1498Szrj }
202938fd1498Szrj #endif
203038fd1498Szrj 
203138fd1498Szrj #if 0
203238fd1498Szrj static void
203338fd1498Szrj dump_prefix_list (FILE *stream, const char *prefix, struct prefix_list *list)
203438fd1498Szrj {
203538fd1498Szrj   while (list)
203638fd1498Szrj     {
203738fd1498Szrj       fprintf (stream, "%s%s,\n", prefix, list->prefix);
203838fd1498Szrj       list = list->next;
203938fd1498Szrj     }
204038fd1498Szrj }
204138fd1498Szrj #endif
204238fd1498Szrj 
204338fd1498Szrj static void
write_list_with_asm(FILE * stream,const char * prefix,struct id * list)204438fd1498Szrj write_list_with_asm (FILE *stream, const char *prefix, struct id *list)
204538fd1498Szrj {
204638fd1498Szrj   while (list)
204738fd1498Szrj     {
204838fd1498Szrj       fprintf (stream, "%sx%d __asm__ (\"%s\");\n",
204938fd1498Szrj 	       prefix, list->sequence, list->name);
205038fd1498Szrj       list = list->next;
205138fd1498Szrj     }
205238fd1498Szrj }
205338fd1498Szrj 
205438fd1498Szrj /* Write out the constructor and destructor tables statically (for a shared
205538fd1498Szrj    object), along with the functions to execute them.  */
205638fd1498Szrj 
205738fd1498Szrj static void
write_c_file_stat(FILE * stream,const char * name ATTRIBUTE_UNUSED)205838fd1498Szrj write_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED)
205938fd1498Szrj {
206038fd1498Szrj   const char *p, *q;
206138fd1498Szrj   char *prefix, *r;
206238fd1498Szrj   int frames = (frame_tables.number > 0);
206338fd1498Szrj 
206438fd1498Szrj   /* Figure out name of output_file, stripping off .so version.  */
206538fd1498Szrj   q = p = lbasename (output_file);
206638fd1498Szrj 
206738fd1498Szrj   while (q)
206838fd1498Szrj     {
206938fd1498Szrj       q = strchr (q,'.');
207038fd1498Szrj       if (q == 0)
207138fd1498Szrj 	{
207238fd1498Szrj 	  q = p + strlen (p);
207338fd1498Szrj 	  break;
207438fd1498Szrj 	}
207538fd1498Szrj       else
207638fd1498Szrj 	{
207738fd1498Szrj 	  if (filename_ncmp (q, SHLIB_SUFFIX, strlen (SHLIB_SUFFIX)) == 0)
207838fd1498Szrj 	    {
207938fd1498Szrj 	      q += strlen (SHLIB_SUFFIX);
208038fd1498Szrj 	      break;
208138fd1498Szrj 	    }
208238fd1498Szrj 	  else
208338fd1498Szrj 	    q++;
208438fd1498Szrj 	}
208538fd1498Szrj     }
208638fd1498Szrj   /* q points to null at end of the string (or . of the .so version) */
208738fd1498Szrj   prefix = XNEWVEC (char, q - p + 1);
208838fd1498Szrj   strncpy (prefix, p, q - p);
208938fd1498Szrj   prefix[q - p] = 0;
209038fd1498Szrj   for (r = prefix; *r; r++)
209138fd1498Szrj     if (!ISALNUM ((unsigned char)*r))
209238fd1498Szrj       *r = '_';
209338fd1498Szrj   if (debug)
209438fd1498Szrj     notice ("\nwrite_c_file - output name is %s, prefix is %s\n",
209538fd1498Szrj 	    output_file, prefix);
209638fd1498Szrj 
209738fd1498Szrj   initname = concat ("_GLOBAL__FI_", prefix, NULL);
209838fd1498Szrj   fininame = concat ("_GLOBAL__FD_", prefix, NULL);
209938fd1498Szrj #ifdef TARGET_AIX_VERSION
210038fd1498Szrj   aix_shared_initname = concat ("_GLOBAL__AIXI_", prefix, NULL);
210138fd1498Szrj   aix_shared_fininame = concat ("_GLOBAL__AIXD_", prefix, NULL);
210238fd1498Szrj #endif
210338fd1498Szrj 
210438fd1498Szrj   free (prefix);
210538fd1498Szrj 
210638fd1498Szrj   /* Write the tables as C code.  */
210738fd1498Szrj 
210838fd1498Szrj   /* This count variable is used to prevent multiple calls to the
210938fd1498Szrj      constructors/destructors.
211038fd1498Szrj      This guard against multiple calls is important on AIX as the initfini
211138fd1498Szrj      functions are deliberately invoked multiple times as part of the
211238fd1498Szrj      mechanisms GCC uses to order constructors across different dependent
211338fd1498Szrj      shared libraries (see config/rs6000/aix.h).
211438fd1498Szrj    */
211538fd1498Szrj   fprintf (stream, "static int count;\n");
211638fd1498Szrj   fprintf (stream, "typedef void entry_pt();\n");
211738fd1498Szrj   write_list_with_asm (stream, "extern entry_pt ", constructors.first);
211838fd1498Szrj 
211938fd1498Szrj   if (frames)
212038fd1498Szrj     {
212138fd1498Szrj       write_list_with_asm (stream, "extern void *", frame_tables.first);
212238fd1498Szrj 
212338fd1498Szrj       fprintf (stream, "\tstatic void *frame_table[] = {\n");
212438fd1498Szrj       write_list (stream, "\t\t&", frame_tables.first);
212538fd1498Szrj       fprintf (stream, "\t0\n};\n");
212638fd1498Szrj 
212738fd1498Szrj       /* This must match what's in frame.h.  */
212838fd1498Szrj       fprintf (stream, "struct object {\n");
212938fd1498Szrj       fprintf (stream, "  void *pc_begin;\n");
213038fd1498Szrj       fprintf (stream, "  void *pc_end;\n");
213138fd1498Szrj       fprintf (stream, "  void *fde_begin;\n");
213238fd1498Szrj       fprintf (stream, "  void *fde_array;\n");
213338fd1498Szrj       fprintf (stream, "  __SIZE_TYPE__ count;\n");
213438fd1498Szrj       fprintf (stream, "  struct object *next;\n");
213538fd1498Szrj       fprintf (stream, "};\n");
213638fd1498Szrj 
213738fd1498Szrj       fprintf (stream, "extern void __register_frame_info_table_bases (void *, struct object *, void *tbase, void *dbase);\n");
213838fd1498Szrj       fprintf (stream, "extern void __register_frame_info_table (void *, struct object *);\n");
213938fd1498Szrj       fprintf (stream, "extern void *__deregister_frame_info (void *);\n");
214038fd1498Szrj #ifdef TARGET_AIX_VERSION
214138fd1498Szrj       fprintf (stream, "extern void *__gcc_unwind_dbase;\n");
214238fd1498Szrj #endif
214338fd1498Szrj 
214438fd1498Szrj       fprintf (stream, "static void reg_frame () {\n");
214538fd1498Szrj       fprintf (stream, "\tstatic struct object ob;\n");
214638fd1498Szrj #ifdef TARGET_AIX_VERSION
214738fd1498Szrj       /* Use __gcc_unwind_dbase as the base address for data on AIX.
214838fd1498Szrj 	 This might not be the start of the segment, signed offsets assumed.
214938fd1498Szrj        */
215038fd1498Szrj       fprintf (stream, "\t__register_frame_info_table_bases (frame_table, &ob, (void *)0, &__gcc_unwind_dbase);\n");
215138fd1498Szrj #else
215238fd1498Szrj       fprintf (stream, "\t__register_frame_info_table (frame_table, &ob);\n");
215338fd1498Szrj #endif
215438fd1498Szrj       fprintf (stream, "\t}\n");
215538fd1498Szrj 
215638fd1498Szrj       fprintf (stream, "static void dereg_frame () {\n");
215738fd1498Szrj       fprintf (stream, "\t__deregister_frame_info (frame_table);\n");
215838fd1498Szrj       fprintf (stream, "\t}\n");
215938fd1498Szrj     }
216038fd1498Szrj 
216138fd1498Szrj   fprintf (stream, "void %s() {\n", initname);
216238fd1498Szrj   if (constructors.number > 0 || frames)
216338fd1498Szrj     {
216438fd1498Szrj       fprintf (stream, "\tstatic entry_pt *ctors[] = {\n");
216538fd1498Szrj       write_list (stream, "\t\t", constructors.first);
216638fd1498Szrj       if (frames)
216738fd1498Szrj 	fprintf (stream, "\treg_frame,\n");
216838fd1498Szrj       fprintf (stream, "\t};\n");
216938fd1498Szrj       fprintf (stream, "\tentry_pt **p;\n");
217038fd1498Szrj       fprintf (stream, "\tif (count++ != 0) return;\n");
217138fd1498Szrj       fprintf (stream, "\tp = ctors + %d;\n", constructors.number + frames);
217238fd1498Szrj       fprintf (stream, "\twhile (p > ctors) (*--p)();\n");
217338fd1498Szrj     }
217438fd1498Szrj   else
217538fd1498Szrj     fprintf (stream, "\t++count;\n");
217638fd1498Szrj   fprintf (stream, "}\n");
217738fd1498Szrj   write_list_with_asm (stream, "extern entry_pt ", destructors.first);
217838fd1498Szrj   fprintf (stream, "void %s() {\n", fininame);
217938fd1498Szrj   if (destructors.number > 0 || frames)
218038fd1498Szrj     {
218138fd1498Szrj       fprintf (stream, "\tstatic entry_pt *dtors[] = {\n");
218238fd1498Szrj       write_list (stream, "\t\t", destructors.first);
218338fd1498Szrj       if (frames)
218438fd1498Szrj 	fprintf (stream, "\tdereg_frame,\n");
218538fd1498Szrj       fprintf (stream, "\t};\n");
218638fd1498Szrj       fprintf (stream, "\tentry_pt **p;\n");
218738fd1498Szrj       fprintf (stream, "\tif (--count != 0) return;\n");
218838fd1498Szrj       fprintf (stream, "\tp = dtors;\n");
218938fd1498Szrj       fprintf (stream, "\twhile (p < dtors + %d) (*p++)();\n",
219038fd1498Szrj 	       destructors.number + frames);
219138fd1498Szrj     }
219238fd1498Szrj   fprintf (stream, "}\n");
219338fd1498Szrj 
219438fd1498Szrj   if (shared_obj)
219538fd1498Szrj     {
219638fd1498Szrj       COLLECT_SHARED_INIT_FUNC (stream, initname);
219738fd1498Szrj       COLLECT_SHARED_FINI_FUNC (stream, fininame);
219838fd1498Szrj     }
219938fd1498Szrj }
220038fd1498Szrj 
220138fd1498Szrj /* Write the constructor/destructor tables.  */
220238fd1498Szrj 
220338fd1498Szrj #ifndef LD_INIT_SWITCH
220438fd1498Szrj static void
write_c_file_glob(FILE * stream,const char * name ATTRIBUTE_UNUSED)220538fd1498Szrj write_c_file_glob (FILE *stream, const char *name ATTRIBUTE_UNUSED)
220638fd1498Szrj {
220738fd1498Szrj   /* Write the tables as C code.  */
220838fd1498Szrj 
220938fd1498Szrj   int frames = (frame_tables.number > 0);
221038fd1498Szrj 
221138fd1498Szrj   fprintf (stream, "typedef void entry_pt();\n\n");
221238fd1498Szrj 
221338fd1498Szrj   write_list_with_asm (stream, "extern entry_pt ", constructors.first);
221438fd1498Szrj 
221538fd1498Szrj   if (frames)
221638fd1498Szrj     {
221738fd1498Szrj       write_list_with_asm (stream, "extern void *", frame_tables.first);
221838fd1498Szrj 
221938fd1498Szrj       fprintf (stream, "\tstatic void *frame_table[] = {\n");
222038fd1498Szrj       write_list (stream, "\t\t&", frame_tables.first);
222138fd1498Szrj       fprintf (stream, "\t0\n};\n");
222238fd1498Szrj 
222338fd1498Szrj       /* This must match what's in frame.h.  */
222438fd1498Szrj       fprintf (stream, "struct object {\n");
222538fd1498Szrj       fprintf (stream, "  void *pc_begin;\n");
222638fd1498Szrj       fprintf (stream, "  void *pc_end;\n");
222738fd1498Szrj       fprintf (stream, "  void *fde_begin;\n");
222838fd1498Szrj       fprintf (stream, "  void *fde_array;\n");
222938fd1498Szrj       fprintf (stream, "  __SIZE_TYPE__ count;\n");
223038fd1498Szrj       fprintf (stream, "  struct object *next;\n");
223138fd1498Szrj       fprintf (stream, "};\n");
223238fd1498Szrj 
223338fd1498Szrj       fprintf (stream, "extern void __register_frame_info_table (void *, struct object *);\n");
223438fd1498Szrj       fprintf (stream, "extern void *__deregister_frame_info (void *);\n");
223538fd1498Szrj 
223638fd1498Szrj       fprintf (stream, "static void reg_frame () {\n");
223738fd1498Szrj       fprintf (stream, "\tstatic struct object ob;\n");
223838fd1498Szrj       fprintf (stream, "\t__register_frame_info_table (frame_table, &ob);\n");
223938fd1498Szrj       fprintf (stream, "\t}\n");
224038fd1498Szrj 
224138fd1498Szrj       fprintf (stream, "static void dereg_frame () {\n");
224238fd1498Szrj       fprintf (stream, "\t__deregister_frame_info (frame_table);\n");
224338fd1498Szrj       fprintf (stream, "\t}\n");
224438fd1498Szrj     }
224538fd1498Szrj 
224638fd1498Szrj   fprintf (stream, "\nentry_pt * __CTOR_LIST__[] = {\n");
224738fd1498Szrj   fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number + frames);
224838fd1498Szrj   write_list (stream, "\t", constructors.first);
224938fd1498Szrj   if (frames)
225038fd1498Szrj     fprintf (stream, "\treg_frame,\n");
225138fd1498Szrj   fprintf (stream, "\t0\n};\n\n");
225238fd1498Szrj 
225338fd1498Szrj   write_list_with_asm (stream, "extern entry_pt ", destructors.first);
225438fd1498Szrj 
225538fd1498Szrj   fprintf (stream, "\nentry_pt * __DTOR_LIST__[] = {\n");
225638fd1498Szrj   fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number + frames);
225738fd1498Szrj   write_list (stream, "\t", destructors.first);
225838fd1498Szrj   if (frames)
225938fd1498Szrj     fprintf (stream, "\tdereg_frame,\n");
226038fd1498Szrj   fprintf (stream, "\t0\n};\n\n");
226138fd1498Szrj 
226238fd1498Szrj   fprintf (stream, "extern entry_pt %s;\n", NAME__MAIN);
226338fd1498Szrj   fprintf (stream, "entry_pt *__main_reference = %s;\n\n", NAME__MAIN);
226438fd1498Szrj }
226538fd1498Szrj #endif /* ! LD_INIT_SWITCH */
226638fd1498Szrj 
226738fd1498Szrj static void
write_c_file(FILE * stream,const char * name)226838fd1498Szrj write_c_file (FILE *stream, const char *name)
226938fd1498Szrj {
227038fd1498Szrj #ifndef LD_INIT_SWITCH
227138fd1498Szrj   if (! shared_obj)
227238fd1498Szrj     write_c_file_glob (stream, name);
227338fd1498Szrj   else
227438fd1498Szrj #endif
227538fd1498Szrj     write_c_file_stat (stream, name);
227638fd1498Szrj }
227738fd1498Szrj 
227838fd1498Szrj #ifdef COLLECT_EXPORT_LIST
227938fd1498Szrj static void
write_aix_file(FILE * stream,struct id * list)228038fd1498Szrj write_aix_file (FILE *stream, struct id *list)
228138fd1498Szrj {
228238fd1498Szrj   for (; list; list = list->next)
228338fd1498Szrj     {
228438fd1498Szrj       fputs (list->name, stream);
228538fd1498Szrj       putc ('\n', stream);
228638fd1498Szrj     }
228738fd1498Szrj }
228838fd1498Szrj #endif
228938fd1498Szrj 
229038fd1498Szrj #ifdef OBJECT_FORMAT_NONE
229138fd1498Szrj 
229238fd1498Szrj /* Check to make sure the file is an LTO object file.  */
229338fd1498Szrj 
229438fd1498Szrj static bool
maybe_lto_object_file(const char * prog_name)229538fd1498Szrj maybe_lto_object_file (const char *prog_name)
229638fd1498Szrj {
229738fd1498Szrj   FILE *f;
229838fd1498Szrj   unsigned char buf[4];
229938fd1498Szrj   int i;
230038fd1498Szrj 
230138fd1498Szrj   static unsigned char elfmagic[4] = { 0x7f, 'E', 'L', 'F' };
230238fd1498Szrj   static unsigned char coffmagic[2] = { 0x4c, 0x01 };
230338fd1498Szrj   static unsigned char coffmagic_x64[2] = { 0x64, 0x86 };
230438fd1498Szrj   static unsigned char machomagic[4][4] = {
230538fd1498Szrj     { 0xcf, 0xfa, 0xed, 0xfe },
230638fd1498Szrj     { 0xce, 0xfa, 0xed, 0xfe },
230738fd1498Szrj     { 0xfe, 0xed, 0xfa, 0xcf },
230838fd1498Szrj     { 0xfe, 0xed, 0xfa, 0xce }
230938fd1498Szrj   };
231038fd1498Szrj 
231138fd1498Szrj   f = fopen (prog_name, "rb");
231238fd1498Szrj   if (f == NULL)
231338fd1498Szrj     return false;
231438fd1498Szrj   if (fread (buf, sizeof (buf), 1, f) != 1)
231538fd1498Szrj     buf[0] = 0;
231638fd1498Szrj   fclose (f);
231738fd1498Szrj 
231838fd1498Szrj   if (memcmp (buf, elfmagic, sizeof (elfmagic)) == 0
231938fd1498Szrj       || memcmp (buf, coffmagic, sizeof (coffmagic)) == 0
232038fd1498Szrj       || memcmp (buf, coffmagic_x64, sizeof (coffmagic_x64)) == 0)
232138fd1498Szrj     return true;
232238fd1498Szrj   for (i = 0; i < 4; i++)
232338fd1498Szrj     if (memcmp (buf, machomagic[i], sizeof (machomagic[i])) == 0)
232438fd1498Szrj       return true;
232538fd1498Szrj 
232638fd1498Szrj   return false;
232738fd1498Szrj }
232838fd1498Szrj 
232938fd1498Szrj /* Generic version to scan the name list of the loaded program for
233038fd1498Szrj    the symbols g++ uses for static constructors and destructors.  */
233138fd1498Szrj 
233238fd1498Szrj static void
scan_prog_file(const char * prog_name,scanpass which_pass,scanfilter filter)233338fd1498Szrj scan_prog_file (const char *prog_name, scanpass which_pass,
233438fd1498Szrj 		scanfilter filter)
233538fd1498Szrj {
233638fd1498Szrj   void (*int_handler) (int);
233738fd1498Szrj #ifdef SIGQUIT
233838fd1498Szrj   void (*quit_handler) (int);
233938fd1498Szrj #endif
234038fd1498Szrj   char *real_nm_argv[4];
234138fd1498Szrj   const char **nm_argv = CONST_CAST2 (const char **, char**, real_nm_argv);
234238fd1498Szrj   int argc = 0;
234338fd1498Szrj   struct pex_obj *pex;
234438fd1498Szrj   const char *errmsg;
234538fd1498Szrj   int err;
234638fd1498Szrj   char *p, buf[1024];
234738fd1498Szrj   FILE *inf;
234838fd1498Szrj   int found_lto = 0;
234938fd1498Szrj 
235038fd1498Szrj   if (which_pass == PASS_SECOND)
235138fd1498Szrj     return;
235238fd1498Szrj 
235338fd1498Szrj   /* LTO objects must be in a known format.  This check prevents
235438fd1498Szrj      us from accepting an archive containing LTO objects, which
235538fd1498Szrj      gcc cannot currently handle.  */
235638fd1498Szrj   if (which_pass == PASS_LTOINFO && !maybe_lto_object_file (prog_name))
235738fd1498Szrj     return;
235838fd1498Szrj 
235938fd1498Szrj   /* If we do not have an `nm', complain.  */
236038fd1498Szrj   if (nm_file_name == 0)
236138fd1498Szrj     fatal_error (input_location, "cannot find 'nm'");
236238fd1498Szrj 
236338fd1498Szrj   nm_argv[argc++] = nm_file_name;
236438fd1498Szrj   if (NM_FLAGS[0] != '\0')
236538fd1498Szrj     nm_argv[argc++] = NM_FLAGS;
236638fd1498Szrj 
236738fd1498Szrj   nm_argv[argc++] = prog_name;
236838fd1498Szrj   nm_argv[argc++] = (char *) 0;
236938fd1498Szrj 
237038fd1498Szrj   /* Trace if needed.  */
237138fd1498Szrj   if (verbose)
237238fd1498Szrj     {
237338fd1498Szrj       const char **p_argv;
237438fd1498Szrj       const char *str;
237538fd1498Szrj 
237638fd1498Szrj       for (p_argv = &nm_argv[0]; (str = *p_argv) != (char *) 0; p_argv++)
237738fd1498Szrj 	fprintf (stderr, " %s", str);
237838fd1498Szrj 
237938fd1498Szrj       fprintf (stderr, "\n");
238038fd1498Szrj     }
238138fd1498Szrj 
238238fd1498Szrj   fflush (stdout);
238338fd1498Szrj   fflush (stderr);
238438fd1498Szrj 
238538fd1498Szrj   pex = pex_init (PEX_USE_PIPES, "collect2", NULL);
238638fd1498Szrj   if (pex == NULL)
238738fd1498Szrj     fatal_error (input_location, "pex_init failed: %m");
238838fd1498Szrj 
238938fd1498Szrj   errmsg = pex_run (pex, 0, nm_file_name, real_nm_argv, NULL, HOST_BIT_BUCKET,
239038fd1498Szrj 		    &err);
239138fd1498Szrj   if (errmsg != NULL)
239238fd1498Szrj     {
239338fd1498Szrj       if (err != 0)
239438fd1498Szrj 	{
239538fd1498Szrj 	  errno = err;
239638fd1498Szrj 	  fatal_error (input_location, "%s: %m", _(errmsg));
239738fd1498Szrj 	}
239838fd1498Szrj       else
239938fd1498Szrj 	fatal_error (input_location, errmsg);
240038fd1498Szrj     }
240138fd1498Szrj 
240238fd1498Szrj   int_handler  = (void (*) (int)) signal (SIGINT,  SIG_IGN);
240338fd1498Szrj #ifdef SIGQUIT
240438fd1498Szrj   quit_handler = (void (*) (int)) signal (SIGQUIT, SIG_IGN);
240538fd1498Szrj #endif
240638fd1498Szrj 
240738fd1498Szrj   inf = pex_read_output (pex, 0);
240838fd1498Szrj   if (inf == NULL)
240938fd1498Szrj     fatal_error (input_location, "can't open nm output: %m");
241038fd1498Szrj 
241138fd1498Szrj   if (debug)
241238fd1498Szrj     {
241338fd1498Szrj       if (which_pass == PASS_LTOINFO)
241438fd1498Szrj         fprintf (stderr, "\nnm output with LTO info marker symbol.\n");
241538fd1498Szrj       else
241638fd1498Szrj         fprintf (stderr, "\nnm output with constructors/destructors.\n");
241738fd1498Szrj     }
241838fd1498Szrj 
241938fd1498Szrj   /* Read each line of nm output.  */
242038fd1498Szrj   while (fgets (buf, sizeof buf, inf) != (char *) 0)
242138fd1498Szrj     {
242238fd1498Szrj       int ch, ch2;
242338fd1498Szrj       char *name, *end;
242438fd1498Szrj 
242538fd1498Szrj       if (debug)
242638fd1498Szrj         fprintf (stderr, "\t%s\n", buf);
242738fd1498Szrj 
242838fd1498Szrj       if (which_pass == PASS_LTOINFO)
242938fd1498Szrj         {
243038fd1498Szrj           if (found_lto)
243138fd1498Szrj             continue;
243238fd1498Szrj 
243338fd1498Szrj           /* Look for the LTO info marker symbol, and add filename to
243438fd1498Szrj              the LTO objects list if found.  */
243538fd1498Szrj           for (p = buf; (ch = *p) != '\0' && ch != '\n'; p++)
243638fd1498Szrj             if (ch == ' '  && p[1] == '_' && p[2] == '_'
243738fd1498Szrj 		&& (strncmp (p + (p[3] == '_' ? 2 : 1), "__gnu_lto_v1", 12) == 0)
243838fd1498Szrj 		&& ISSPACE (p[p[3] == '_' ? 14 : 13]))
243938fd1498Szrj               {
244038fd1498Szrj                 add_lto_object (&lto_objects, prog_name);
244138fd1498Szrj 
244238fd1498Szrj                 /* We need to read all the input, so we can't just
244338fd1498Szrj                    return here.  But we can avoid useless work.  */
244438fd1498Szrj                 found_lto = 1;
244538fd1498Szrj 
244638fd1498Szrj                 break;
244738fd1498Szrj               }
244838fd1498Szrj 
244938fd1498Szrj 	  continue;
245038fd1498Szrj         }
245138fd1498Szrj 
245238fd1498Szrj       /* If it contains a constructor or destructor name, add the name
245338fd1498Szrj 	 to the appropriate list unless this is a kind of symbol we're
245438fd1498Szrj 	 not supposed to even consider.  */
245538fd1498Szrj 
245638fd1498Szrj       for (p = buf; (ch = *p) != '\0' && ch != '\n' && ch != '_'; p++)
245738fd1498Szrj 	if (ch == ' ' && p[1] == 'U' && p[2] == ' ')
245838fd1498Szrj 	  break;
245938fd1498Szrj 
246038fd1498Szrj       if (ch != '_')
246138fd1498Szrj 	continue;
246238fd1498Szrj 
246338fd1498Szrj       name = p;
246438fd1498Szrj       /* Find the end of the symbol name.
246538fd1498Szrj 	 Do not include `|', because Encore nm can tack that on the end.  */
246638fd1498Szrj       for (end = p; (ch2 = *end) != '\0' && !ISSPACE (ch2) && ch2 != '|';
246738fd1498Szrj 	   end++)
246838fd1498Szrj 	continue;
246938fd1498Szrj 
247038fd1498Szrj 
247138fd1498Szrj       *end = '\0';
247238fd1498Szrj 
247338fd1498Szrj       switch (is_ctor_dtor (name))
247438fd1498Szrj 	{
247538fd1498Szrj 	case SYM_CTOR:
247638fd1498Szrj 	  if (! (filter & SCAN_CTOR))
247738fd1498Szrj 	    break;
247838fd1498Szrj 	  if (which_pass != PASS_LIB)
247938fd1498Szrj 	    add_to_list (&constructors, name);
248038fd1498Szrj 	  break;
248138fd1498Szrj 
248238fd1498Szrj 	case SYM_DTOR:
248338fd1498Szrj 	  if (! (filter & SCAN_DTOR))
248438fd1498Szrj 	    break;
248538fd1498Szrj 	  if (which_pass != PASS_LIB)
248638fd1498Szrj 	    add_to_list (&destructors, name);
248738fd1498Szrj 	  break;
248838fd1498Szrj 
248938fd1498Szrj 	case SYM_INIT:
249038fd1498Szrj 	  if (! (filter & SCAN_INIT))
249138fd1498Szrj 	    break;
249238fd1498Szrj 	  if (which_pass != PASS_LIB)
249338fd1498Szrj 	    fatal_error (input_location, "init function found in object %s",
249438fd1498Szrj 			 prog_name);
249538fd1498Szrj #ifndef LD_INIT_SWITCH
249638fd1498Szrj 	  add_to_list (&constructors, name);
249738fd1498Szrj #endif
249838fd1498Szrj 	  break;
249938fd1498Szrj 
250038fd1498Szrj 	case SYM_FINI:
250138fd1498Szrj 	  if (! (filter & SCAN_FINI))
250238fd1498Szrj 	    break;
250338fd1498Szrj 	  if (which_pass != PASS_LIB)
250438fd1498Szrj 	    fatal_error (input_location, "fini function found in object %s",
250538fd1498Szrj 			 prog_name);
250638fd1498Szrj #ifndef LD_FINI_SWITCH
250738fd1498Szrj 	  add_to_list (&destructors, name);
250838fd1498Szrj #endif
250938fd1498Szrj 	  break;
251038fd1498Szrj 
251138fd1498Szrj 	case SYM_DWEH:
251238fd1498Szrj 	  if (! (filter & SCAN_DWEH))
251338fd1498Szrj 	    break;
251438fd1498Szrj 	  if (which_pass != PASS_LIB)
251538fd1498Szrj 	    add_to_list (&frame_tables, name);
251638fd1498Szrj 	  break;
251738fd1498Szrj 
251838fd1498Szrj 	default:		/* not a constructor or destructor */
251938fd1498Szrj 	  continue;
252038fd1498Szrj 	}
252138fd1498Szrj     }
252238fd1498Szrj 
252338fd1498Szrj   if (debug)
252438fd1498Szrj     fprintf (stderr, "\n");
252538fd1498Szrj 
252638fd1498Szrj   do_wait (nm_file_name, pex);
252738fd1498Szrj 
252838fd1498Szrj   signal (SIGINT,  int_handler);
252938fd1498Szrj #ifdef SIGQUIT
253038fd1498Szrj   signal (SIGQUIT, quit_handler);
253138fd1498Szrj #endif
253238fd1498Szrj }
253338fd1498Szrj 
253438fd1498Szrj #ifdef LDD_SUFFIX
253538fd1498Szrj 
253638fd1498Szrj /* Use the List Dynamic Dependencies program to find shared libraries that
253738fd1498Szrj    the output file depends upon and their initialization/finalization
253838fd1498Szrj    routines, if any.  */
253938fd1498Szrj 
254038fd1498Szrj static void
scan_libraries(const char * prog_name)254138fd1498Szrj scan_libraries (const char *prog_name)
254238fd1498Szrj {
254338fd1498Szrj   static struct head libraries;		/* list of shared libraries found */
254438fd1498Szrj   struct id *list;
254538fd1498Szrj   void (*int_handler) (int);
254638fd1498Szrj #ifdef SIGQUIT
254738fd1498Szrj   void (*quit_handler) (int);
254838fd1498Szrj #endif
254938fd1498Szrj   char *real_ldd_argv[4];
255038fd1498Szrj   const char **ldd_argv = CONST_CAST2 (const char **, char **, real_ldd_argv);
255138fd1498Szrj   int argc = 0;
255238fd1498Szrj   struct pex_obj *pex;
255338fd1498Szrj   const char *errmsg;
255438fd1498Szrj   int err;
255538fd1498Szrj   char buf[1024];
255638fd1498Szrj   FILE *inf;
255738fd1498Szrj 
255838fd1498Szrj   /* If we do not have an `ldd', complain.  */
255938fd1498Szrj   if (ldd_file_name == 0)
256038fd1498Szrj     {
256138fd1498Szrj       error ("cannot find 'ldd'");
256238fd1498Szrj       return;
256338fd1498Szrj     }
256438fd1498Szrj 
256538fd1498Szrj   ldd_argv[argc++] = ldd_file_name;
256638fd1498Szrj   ldd_argv[argc++] = prog_name;
256738fd1498Szrj   ldd_argv[argc++] = (char *) 0;
256838fd1498Szrj 
256938fd1498Szrj   /* Trace if needed.  */
257038fd1498Szrj   if (verbose)
257138fd1498Szrj     {
257238fd1498Szrj       const char **p_argv;
257338fd1498Szrj       const char *str;
257438fd1498Szrj 
257538fd1498Szrj       for (p_argv = &ldd_argv[0]; (str = *p_argv) != (char *) 0; p_argv++)
257638fd1498Szrj 	fprintf (stderr, " %s", str);
257738fd1498Szrj 
257838fd1498Szrj       fprintf (stderr, "\n");
257938fd1498Szrj     }
258038fd1498Szrj 
258138fd1498Szrj   fflush (stdout);
258238fd1498Szrj   fflush (stderr);
258338fd1498Szrj 
258438fd1498Szrj   pex = pex_init (PEX_USE_PIPES, "collect2", NULL);
258538fd1498Szrj   if (pex == NULL)
258638fd1498Szrj     fatal_error (input_location, "pex_init failed: %m");
258738fd1498Szrj 
258838fd1498Szrj   errmsg = pex_run (pex, 0, ldd_file_name, real_ldd_argv, NULL, NULL, &err);
258938fd1498Szrj   if (errmsg != NULL)
259038fd1498Szrj     {
259138fd1498Szrj       if (err != 0)
259238fd1498Szrj 	{
259338fd1498Szrj 	  errno = err;
259438fd1498Szrj 	  fatal_error (input_location, "%s: %m", _(errmsg));
259538fd1498Szrj 	}
259638fd1498Szrj       else
259738fd1498Szrj 	fatal_error (input_location, errmsg);
259838fd1498Szrj     }
259938fd1498Szrj 
260038fd1498Szrj   int_handler  = (void (*) (int)) signal (SIGINT,  SIG_IGN);
260138fd1498Szrj #ifdef SIGQUIT
260238fd1498Szrj   quit_handler = (void (*) (int)) signal (SIGQUIT, SIG_IGN);
260338fd1498Szrj #endif
260438fd1498Szrj 
260538fd1498Szrj   inf = pex_read_output (pex, 0);
260638fd1498Szrj   if (inf == NULL)
260738fd1498Szrj     fatal_error (input_location, "can't open ldd output: %m");
260838fd1498Szrj 
260938fd1498Szrj   if (debug)
261038fd1498Szrj     notice ("\nldd output with constructors/destructors.\n");
261138fd1498Szrj 
261238fd1498Szrj   /* Read each line of ldd output.  */
261338fd1498Szrj   while (fgets (buf, sizeof buf, inf) != (char *) 0)
261438fd1498Szrj     {
261538fd1498Szrj       int ch2;
261638fd1498Szrj       char *name, *end, *p = buf;
261738fd1498Szrj 
261838fd1498Szrj       /* Extract names of libraries and add to list.  */
261938fd1498Szrj       PARSE_LDD_OUTPUT (p);
262038fd1498Szrj       if (p == 0)
262138fd1498Szrj 	continue;
262238fd1498Szrj 
262338fd1498Szrj       name = p;
262438fd1498Szrj       if (strncmp (name, "not found", sizeof ("not found") - 1) == 0)
262538fd1498Szrj 	fatal_error (input_location, "dynamic dependency %s not found", buf);
262638fd1498Szrj 
262738fd1498Szrj       /* Find the end of the symbol name.  */
262838fd1498Szrj       for (end = p;
262938fd1498Szrj 	   (ch2 = *end) != '\0' && ch2 != '\n' && !ISSPACE (ch2) && ch2 != '|';
263038fd1498Szrj 	   end++)
263138fd1498Szrj 	continue;
263238fd1498Szrj       *end = '\0';
263338fd1498Szrj 
263438fd1498Szrj       if (access (name, R_OK) == 0)
263538fd1498Szrj 	add_to_list (&libraries, name);
263638fd1498Szrj       else
263738fd1498Szrj 	fatal_error (input_location, "unable to open dynamic dependency '%s'",
263838fd1498Szrj 		     buf);
263938fd1498Szrj 
264038fd1498Szrj       if (debug)
264138fd1498Szrj 	fprintf (stderr, "\t%s\n", buf);
264238fd1498Szrj     }
264338fd1498Szrj   if (debug)
264438fd1498Szrj     fprintf (stderr, "\n");
264538fd1498Szrj 
264638fd1498Szrj   do_wait (ldd_file_name, pex);
264738fd1498Szrj 
264838fd1498Szrj   signal (SIGINT,  int_handler);
264938fd1498Szrj #ifdef SIGQUIT
265038fd1498Szrj   signal (SIGQUIT, quit_handler);
265138fd1498Szrj #endif
265238fd1498Szrj 
265338fd1498Szrj   /* Now iterate through the library list adding their symbols to
265438fd1498Szrj      the list.  */
265538fd1498Szrj   for (list = libraries.first; list; list = list->next)
265638fd1498Szrj     scan_prog_file (list->name, PASS_LIB, SCAN_ALL);
265738fd1498Szrj }
265838fd1498Szrj 
265938fd1498Szrj #endif /* LDD_SUFFIX */
266038fd1498Szrj 
266138fd1498Szrj #endif /* OBJECT_FORMAT_NONE */
266238fd1498Szrj 
266338fd1498Szrj 
266438fd1498Szrj /*
266538fd1498Szrj  * COFF specific stuff.
266638fd1498Szrj  */
266738fd1498Szrj 
266838fd1498Szrj #ifdef OBJECT_FORMAT_COFF
266938fd1498Szrj 
267038fd1498Szrj #   define GCC_SYMBOLS(X)	(HEADER (ldptr).f_nsyms)
267138fd1498Szrj #   define GCC_SYMENT		SYMENT
267238fd1498Szrj #   if defined (C_WEAKEXT)
267338fd1498Szrj #     define GCC_OK_SYMBOL(X) \
267438fd1498Szrj        (((X).n_sclass == C_EXT || (X).n_sclass == C_WEAKEXT) && \
267538fd1498Szrj 	((X).n_scnum > N_UNDEF) && \
267638fd1498Szrj 	(aix64_flag \
267738fd1498Szrj 	 || (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) \
267838fd1498Szrj 	     || ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT))))
267938fd1498Szrj #     define GCC_UNDEF_SYMBOL(X) \
268038fd1498Szrj        (((X).n_sclass == C_EXT || (X).n_sclass == C_WEAKEXT) && \
268138fd1498Szrj 	((X).n_scnum == N_UNDEF))
268238fd1498Szrj #   else
268338fd1498Szrj #     define GCC_OK_SYMBOL(X) \
268438fd1498Szrj        (((X).n_sclass == C_EXT) && \
268538fd1498Szrj 	((X).n_scnum > N_UNDEF) && \
268638fd1498Szrj 	(aix64_flag \
268738fd1498Szrj 	 || (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) \
268838fd1498Szrj 	     || ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT))))
268938fd1498Szrj #     define GCC_UNDEF_SYMBOL(X) \
269038fd1498Szrj        (((X).n_sclass == C_EXT) && ((X).n_scnum == N_UNDEF))
269138fd1498Szrj #   endif
269238fd1498Szrj #   define GCC_SYMINC(X)	((X).n_numaux+1)
269338fd1498Szrj #   define GCC_SYMZERO(X)	0
269438fd1498Szrj 
269538fd1498Szrj /* 0757 = U803XTOCMAGIC (AIX 4.3) and 0767 = U64_TOCMAGIC (AIX V5) */
269638fd1498Szrj #if TARGET_AIX_VERSION >= 51
269738fd1498Szrj #   define GCC_CHECK_HDR(X) \
269838fd1498Szrj      (((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \
269938fd1498Szrj        || (HEADER (X).f_magic == 0767 && aix64_flag)) \
270038fd1498Szrj       && !(HEADER (X).f_flags & F_LOADONLY))
270138fd1498Szrj #else
270238fd1498Szrj #   define GCC_CHECK_HDR(X) \
270338fd1498Szrj      (((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \
270438fd1498Szrj        || (HEADER (X).f_magic == 0757 && aix64_flag)) \
270538fd1498Szrj       && !(HEADER (X).f_flags & F_LOADONLY))
270638fd1498Szrj #endif
270738fd1498Szrj 
270838fd1498Szrj #ifdef COLLECT_EXPORT_LIST
270938fd1498Szrj /* Array of standard AIX libraries which should not
271038fd1498Szrj    be scanned for ctors/dtors.  */
271138fd1498Szrj static const char *const aix_std_libs[] = {
271238fd1498Szrj   "/unix",
271338fd1498Szrj   "/lib/libc.a",
271438fd1498Szrj   "/lib/libm.a",
271538fd1498Szrj   "/lib/libc_r.a",
271638fd1498Szrj   "/lib/libm_r.a",
271738fd1498Szrj   "/usr/lib/libc.a",
271838fd1498Szrj   "/usr/lib/libm.a",
271938fd1498Szrj   "/usr/lib/libc_r.a",
272038fd1498Szrj   "/usr/lib/libm_r.a",
272138fd1498Szrj   "/usr/lib/threads/libc.a",
272238fd1498Szrj   "/usr/ccs/lib/libc.a",
272338fd1498Szrj   "/usr/ccs/lib/libm.a",
272438fd1498Szrj   "/usr/ccs/lib/libc_r.a",
272538fd1498Szrj   "/usr/ccs/lib/libm_r.a",
272638fd1498Szrj   NULL
272738fd1498Szrj };
272838fd1498Szrj 
272938fd1498Szrj /* This function checks the filename and returns 1
273038fd1498Szrj    if this name matches the location of a standard AIX library.  */
273138fd1498Szrj static int ignore_library (const char *);
273238fd1498Szrj static int
ignore_library(const char * name)273338fd1498Szrj ignore_library (const char *name)
273438fd1498Szrj {
273538fd1498Szrj   const char *const *p;
273638fd1498Szrj   size_t length;
273738fd1498Szrj 
273838fd1498Szrj   if (target_system_root[0] != '\0')
273938fd1498Szrj     {
274038fd1498Szrj       length = strlen (target_system_root);
274138fd1498Szrj       if (strncmp (name, target_system_root, length) != 0)
274238fd1498Szrj 	return 0;
274338fd1498Szrj       name += length;
274438fd1498Szrj     }
274538fd1498Szrj   for (p = &aix_std_libs[0]; *p != NULL; ++p)
274638fd1498Szrj     if (strcmp (name, *p) == 0)
274738fd1498Szrj       return 1;
274838fd1498Szrj   return 0;
274938fd1498Szrj }
275038fd1498Szrj #endif /* COLLECT_EXPORT_LIST */
275138fd1498Szrj 
275238fd1498Szrj #if defined (HAVE_DECL_LDGETNAME) && !HAVE_DECL_LDGETNAME
275338fd1498Szrj extern char *ldgetname (LDFILE *, GCC_SYMENT *);
275438fd1498Szrj #endif
275538fd1498Szrj 
275638fd1498Szrj /* COFF version to scan the name list of the loaded program for
275738fd1498Szrj    the symbols g++ uses for static constructors and destructors.  */
275838fd1498Szrj 
275938fd1498Szrj static void
scan_prog_file(const char * prog_name,scanpass which_pass,scanfilter filter)276038fd1498Szrj scan_prog_file (const char *prog_name, scanpass which_pass,
276138fd1498Szrj 		scanfilter filter)
276238fd1498Szrj {
276338fd1498Szrj   LDFILE *ldptr = NULL;
276438fd1498Szrj   int sym_index, sym_count;
276538fd1498Szrj   int is_shared = 0;
276638fd1498Szrj   int found_lto = 0;
276738fd1498Szrj 
276838fd1498Szrj   if (which_pass != PASS_FIRST && which_pass != PASS_OBJ
276938fd1498Szrj       && which_pass != PASS_LTOINFO)
277038fd1498Szrj     return;
277138fd1498Szrj 
277238fd1498Szrj #ifdef COLLECT_EXPORT_LIST
277338fd1498Szrj   /* We do not need scanning for some standard C libraries.  */
277438fd1498Szrj   if (which_pass == PASS_FIRST && ignore_library (prog_name))
277538fd1498Szrj     return;
277638fd1498Szrj 
277738fd1498Szrj   /* On AIX we have a loop, because there is not much difference
277838fd1498Szrj      between an object and an archive. This trick allows us to
277938fd1498Szrj      eliminate scan_libraries() function.  */
278038fd1498Szrj   do
278138fd1498Szrj     {
278238fd1498Szrj       found_lto = 0;
278338fd1498Szrj #endif
278438fd1498Szrj       /* Some platforms (e.g. OSF4) declare ldopen as taking a
278538fd1498Szrj 	 non-const char * filename parameter, even though it will not
278638fd1498Szrj 	 modify that string.  So we must cast away const-ness here,
278738fd1498Szrj 	 using CONST_CAST to prevent complaints from -Wcast-qual.  */
278838fd1498Szrj       if ((ldptr = ldopen (CONST_CAST (char *, prog_name), ldptr)) != NULL)
278938fd1498Szrj 	{
279038fd1498Szrj 	  if (! MY_ISCOFF (HEADER (ldptr).f_magic))
279138fd1498Szrj 	    fatal_error (input_location, "%s: not a COFF file", prog_name);
279238fd1498Szrj 
279338fd1498Szrj 	  if (GCC_CHECK_HDR (ldptr))
279438fd1498Szrj 	    {
279538fd1498Szrj 	      sym_count = GCC_SYMBOLS (ldptr);
279638fd1498Szrj 	      sym_index = GCC_SYMZERO (ldptr);
279738fd1498Szrj 
279838fd1498Szrj #ifdef COLLECT_EXPORT_LIST
279938fd1498Szrj 	      /* Is current archive member a shared object?  */
280038fd1498Szrj 	      is_shared = HEADER (ldptr).f_flags & F_SHROBJ;
280138fd1498Szrj #endif
280238fd1498Szrj 
280338fd1498Szrj 	      while (sym_index < sym_count)
280438fd1498Szrj 		{
280538fd1498Szrj 		  GCC_SYMENT symbol;
280638fd1498Szrj 
280738fd1498Szrj 		  if (ldtbread (ldptr, sym_index, &symbol) <= 0)
280838fd1498Szrj 		    break;
280938fd1498Szrj 		  sym_index += GCC_SYMINC (symbol);
281038fd1498Szrj 
281138fd1498Szrj 		  if (GCC_OK_SYMBOL (symbol))
281238fd1498Szrj 		    {
281338fd1498Szrj 		      char *name;
281438fd1498Szrj 
281538fd1498Szrj 		      if ((name = ldgetname (ldptr, &symbol)) == NULL)
281638fd1498Szrj 			continue;		/* Should never happen.  */
281738fd1498Szrj 
281838fd1498Szrj #ifdef XCOFF_DEBUGGING_INFO
281938fd1498Szrj 		      /* All AIX function names have a duplicate entry
282038fd1498Szrj 			 beginning with a dot.  */
282138fd1498Szrj 		      if (*name == '.')
282238fd1498Szrj 			++name;
282338fd1498Szrj #endif
282438fd1498Szrj 
282538fd1498Szrj                       if (which_pass == PASS_LTOINFO)
282638fd1498Szrj                         {
282738fd1498Szrj 			  if (found_lto)
282838fd1498Szrj 			    continue;
282938fd1498Szrj 			  if (strncmp (name, "__gnu_lto_v1", 12) == 0)
283038fd1498Szrj 			    {
283138fd1498Szrj 			      add_lto_object (&lto_objects, prog_name);
283238fd1498Szrj 			      found_lto = 1;
283338fd1498Szrj 			      break;
283438fd1498Szrj 			    }
283538fd1498Szrj 			  continue;
283638fd1498Szrj 			}
283738fd1498Szrj 
283838fd1498Szrj 		      switch (is_ctor_dtor (name))
283938fd1498Szrj 			{
284038fd1498Szrj #if TARGET_AIX_VERSION
284138fd1498Szrj 		      /* Add AIX shared library initalisers/finalisers
284238fd1498Szrj 			 to the constructors/destructors list of the
284338fd1498Szrj 			 current module.  */
284438fd1498Szrj 			case SYM_AIXI:
284538fd1498Szrj 			  if (! (filter & SCAN_CTOR))
284638fd1498Szrj 			    break;
2847*58e805e6Szrj 			  if (is_shared && !aixlazy_flag
2848*58e805e6Szrj #ifdef COLLECT_EXPORT_LIST
2849*58e805e6Szrj 			      && ! static_obj
2850*58e805e6Szrj 			      && ! is_in_list (prog_name, static_libs.first)
2851*58e805e6Szrj #endif
2852*58e805e6Szrj 			      )
285338fd1498Szrj 			    add_to_list (&constructors, name);
285438fd1498Szrj 			  break;
285538fd1498Szrj 
285638fd1498Szrj 			case SYM_AIXD:
285738fd1498Szrj 			  if (! (filter & SCAN_DTOR))
285838fd1498Szrj 			    break;
285938fd1498Szrj 			  if (is_shared && !aixlazy_flag)
286038fd1498Szrj 			    add_to_list (&destructors, name);
286138fd1498Szrj 			  break;
286238fd1498Szrj #endif
286338fd1498Szrj 
286438fd1498Szrj 			case SYM_CTOR:
286538fd1498Szrj 			  if (! (filter & SCAN_CTOR))
286638fd1498Szrj 			    break;
286738fd1498Szrj 			  if (! is_shared)
286838fd1498Szrj 			    add_to_list (&constructors, name);
286938fd1498Szrj #if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
287038fd1498Szrj 			  if (which_pass == PASS_OBJ)
287138fd1498Szrj 			    add_to_list (&exports, name);
287238fd1498Szrj #endif
287338fd1498Szrj 			  break;
287438fd1498Szrj 
287538fd1498Szrj 			case SYM_DTOR:
287638fd1498Szrj 			  if (! (filter & SCAN_DTOR))
287738fd1498Szrj 			    break;
287838fd1498Szrj 			  if (! is_shared)
287938fd1498Szrj 			    add_to_list (&destructors, name);
288038fd1498Szrj #if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
288138fd1498Szrj 			  if (which_pass == PASS_OBJ)
288238fd1498Szrj 			    add_to_list (&exports, name);
288338fd1498Szrj #endif
288438fd1498Szrj 			  break;
288538fd1498Szrj 
288638fd1498Szrj #ifdef COLLECT_EXPORT_LIST
288738fd1498Szrj 			case SYM_INIT:
288838fd1498Szrj 			  if (! (filter & SCAN_INIT))
288938fd1498Szrj 			    break;
289038fd1498Szrj #ifndef LD_INIT_SWITCH
289138fd1498Szrj 			  if (is_shared)
289238fd1498Szrj 			    add_to_list (&constructors, name);
289338fd1498Szrj #endif
289438fd1498Szrj 			  break;
289538fd1498Szrj 
289638fd1498Szrj 			case SYM_FINI:
289738fd1498Szrj 			  if (! (filter & SCAN_FINI))
289838fd1498Szrj 			    break;
289938fd1498Szrj #ifndef LD_INIT_SWITCH
290038fd1498Szrj 			  if (is_shared)
290138fd1498Szrj 			    add_to_list (&destructors, name);
290238fd1498Szrj #endif
290338fd1498Szrj 			  break;
290438fd1498Szrj #endif
290538fd1498Szrj 
290638fd1498Szrj 			case SYM_DWEH:
290738fd1498Szrj 			  if (! (filter & SCAN_DWEH))
290838fd1498Szrj 			    break;
290938fd1498Szrj 			  if (! is_shared)
291038fd1498Szrj 			    add_to_list (&frame_tables, name);
291138fd1498Szrj #if defined (COLLECT_EXPORT_LIST) && !defined (LD_INIT_SWITCH)
291238fd1498Szrj 			  if (which_pass == PASS_OBJ)
291338fd1498Szrj 			    add_to_list (&exports, name);
291438fd1498Szrj #endif
291538fd1498Szrj 			  break;
291638fd1498Szrj 
291738fd1498Szrj 			default:	/* not a constructor or destructor */
291838fd1498Szrj #ifdef COLLECT_EXPORT_LIST
291938fd1498Szrj 			  /* Explicitly export all global symbols when
292038fd1498Szrj 			     building a shared object on AIX, but do not
292138fd1498Szrj 			     re-export symbols from another shared object
292238fd1498Szrj 			     and do not export symbols if the user
292338fd1498Szrj 			     provides an explicit export list.  */
292438fd1498Szrj 			  if (shared_obj && !is_shared
292538fd1498Szrj 			      && which_pass == PASS_OBJ && !export_flag)
292638fd1498Szrj 			    {
292738fd1498Szrj 			      /* Do not auto-export __dso_handle or
292838fd1498Szrj 				 __gcc_unwind_dbase.  They are required
292938fd1498Szrj 				 to be local to each module.  */
293038fd1498Szrj 			      if (strcmp(name, "__dso_handle") != 0
293138fd1498Szrj 				  && strcmp(name, "__gcc_unwind_dbase") != 0)
293238fd1498Szrj 				{
293338fd1498Szrj 				  add_to_list (&exports, name);
293438fd1498Szrj 				}
293538fd1498Szrj 			    }
293638fd1498Szrj #endif
293738fd1498Szrj 			  continue;
293838fd1498Szrj 			}
293938fd1498Szrj 
294038fd1498Szrj 		      if (debug)
294138fd1498Szrj 			fprintf (stderr, "\tsec=%d class=%d type=%s%o %s\n",
294238fd1498Szrj 				 symbol.n_scnum, symbol.n_sclass,
294338fd1498Szrj 				 (symbol.n_type ? "0" : ""), symbol.n_type,
294438fd1498Szrj 				 name);
294538fd1498Szrj 		    }
294638fd1498Szrj 		}
294738fd1498Szrj 	    }
294838fd1498Szrj #ifdef COLLECT_EXPORT_LIST
294938fd1498Szrj 	  else
295038fd1498Szrj 	    {
295138fd1498Szrj 	      /* If archive contains both 32-bit and 64-bit objects,
295238fd1498Szrj 		 we want to skip objects in other mode so mismatch normal.  */
295338fd1498Szrj 	      if (debug)
295438fd1498Szrj 		fprintf (stderr, "%s : magic=%o aix64=%d mismatch\n",
295538fd1498Szrj 			 prog_name, HEADER (ldptr).f_magic, aix64_flag);
295638fd1498Szrj 	    }
295738fd1498Szrj #endif
295838fd1498Szrj 	}
295938fd1498Szrj       else
296038fd1498Szrj 	{
296138fd1498Szrj 	  fatal_error (input_location, "%s: cannot open as COFF file",
296238fd1498Szrj 		       prog_name);
296338fd1498Szrj 	}
296438fd1498Szrj #ifdef COLLECT_EXPORT_LIST
296538fd1498Szrj       /* On AIX loop continues while there are more members in archive.  */
296638fd1498Szrj     }
296738fd1498Szrj   while (ldclose (ldptr) == FAILURE);
296838fd1498Szrj #else
296938fd1498Szrj   /* Otherwise we simply close ldptr.  */
297038fd1498Szrj   (void) ldclose (ldptr);
297138fd1498Szrj #endif
297238fd1498Szrj }
297338fd1498Szrj #endif /* OBJECT_FORMAT_COFF */
297438fd1498Szrj 
297538fd1498Szrj #ifdef COLLECT_EXPORT_LIST
297638fd1498Szrj /* Given a library name without "lib" prefix, this function
297738fd1498Szrj    returns a full library name including a path.  */
297838fd1498Szrj static char *
resolve_lib_name(const char * name)297938fd1498Szrj resolve_lib_name (const char *name)
298038fd1498Szrj {
298138fd1498Szrj   char *lib_buf;
298238fd1498Szrj   int i, j, l = 0;
298338fd1498Szrj   /* Library extensions for AIX dynamic linking.  */
298438fd1498Szrj   const char * const libexts[2] = {"a", "so"};
298538fd1498Szrj 
298638fd1498Szrj   for (i = 0; libpaths[i]; i++)
298738fd1498Szrj     if (libpaths[i]->max_len > l)
298838fd1498Szrj       l = libpaths[i]->max_len;
298938fd1498Szrj 
299038fd1498Szrj   lib_buf = XNEWVEC (char, l + strlen (name) + 10);
299138fd1498Szrj 
299238fd1498Szrj   for (i = 0; libpaths[i]; i++)
299338fd1498Szrj     {
299438fd1498Szrj       struct prefix_list *list = libpaths[i]->plist;
299538fd1498Szrj       for (; list; list = list->next)
299638fd1498Szrj 	{
299738fd1498Szrj 	  /* The following lines are needed because path_prefix list
299838fd1498Szrj 	     may contain directories both with trailing DIR_SEPARATOR and
299938fd1498Szrj 	     without it.  */
300038fd1498Szrj 	  const char *p = "";
300138fd1498Szrj 	  if (!IS_DIR_SEPARATOR (list->prefix[strlen (list->prefix)-1]))
300238fd1498Szrj 	    p = "/";
300338fd1498Szrj 	  for (j = 0; j < 2; j++)
300438fd1498Szrj 	    {
300538fd1498Szrj 	      sprintf (lib_buf, "%s%slib%s.%s",
300638fd1498Szrj 		       list->prefix, p, name,
300738fd1498Szrj 		       libexts[(j + aixrtl_flag) % 2]);
300838fd1498Szrj 	      if (debug) fprintf (stderr, "searching for: %s\n", lib_buf);
300938fd1498Szrj 	      if (file_exists (lib_buf))
301038fd1498Szrj 		{
301138fd1498Szrj 		  if (debug) fprintf (stderr, "found: %s\n", lib_buf);
301238fd1498Szrj 		  return (lib_buf);
301338fd1498Szrj 		}
301438fd1498Szrj 	    }
301538fd1498Szrj 	}
301638fd1498Szrj     }
301738fd1498Szrj   if (debug)
301838fd1498Szrj     fprintf (stderr, "not found\n");
301938fd1498Szrj   else
302038fd1498Szrj     fatal_error (input_location, "library lib%s not found", name);
302138fd1498Szrj   return (NULL);
302238fd1498Szrj }
302338fd1498Szrj #endif /* COLLECT_EXPORT_LIST */
302438fd1498Szrj 
302538fd1498Szrj #ifdef COLLECT_RUN_DSYMUTIL
302638fd1498Szrj static int flag_dsym = false;
302738fd1498Szrj static int flag_idsym = false;
302838fd1498Szrj 
302938fd1498Szrj static void
process_args(int * argcp,char ** argv)303038fd1498Szrj process_args (int *argcp, char **argv) {
303138fd1498Szrj   int i, j;
303238fd1498Szrj   int argc = *argcp;
303338fd1498Szrj   for (i=0; i<argc; ++i)
303438fd1498Szrj     {
303538fd1498Szrj       if (strcmp (argv[i], "-dsym") == 0)
303638fd1498Szrj 	{
303738fd1498Szrj 	  flag_dsym = true;
303838fd1498Szrj 	  /* Remove the flag, as we handle all processing for it.  */
303938fd1498Szrj 	  j = i;
304038fd1498Szrj 	  do
304138fd1498Szrj 	    argv[j] = argv[j+1];
304238fd1498Szrj 	  while (++j < argc);
304338fd1498Szrj 	  --i;
304438fd1498Szrj 	  argc = --(*argcp);
304538fd1498Szrj 	}
304638fd1498Szrj       else if (strcmp (argv[i], "-idsym") == 0)
304738fd1498Szrj 	{
304838fd1498Szrj 	  flag_idsym = true;
304938fd1498Szrj 	  /* Remove the flag, as we handle all processing for it.  */
305038fd1498Szrj 	  j = i;
305138fd1498Szrj 	  do
305238fd1498Szrj 	    argv[j] = argv[j+1];
305338fd1498Szrj 	  while (++j < argc);
305438fd1498Szrj 	  --i;
305538fd1498Szrj 	  argc = --(*argcp);
305638fd1498Szrj 	}
305738fd1498Szrj     }
305838fd1498Szrj }
305938fd1498Szrj 
306038fd1498Szrj static void
do_dsymutil(const char * output_file)306138fd1498Szrj do_dsymutil (const char *output_file) {
306238fd1498Szrj   const char *dsymutil = DSYMUTIL + 1;
306338fd1498Szrj   struct pex_obj *pex;
306438fd1498Szrj   char **real_argv = XCNEWVEC (char *, 3);
306538fd1498Szrj   const char ** argv = CONST_CAST2 (const char **, char **,
306638fd1498Szrj 				    real_argv);
306738fd1498Szrj 
306838fd1498Szrj   argv[0] = dsymutil;
306938fd1498Szrj   argv[1] = output_file;
307038fd1498Szrj   argv[2] = (char *) 0;
307138fd1498Szrj 
307238fd1498Szrj   pex = collect_execute (dsymutil, real_argv, NULL, NULL,
307338fd1498Szrj 			 PEX_LAST | PEX_SEARCH, false);
307438fd1498Szrj   do_wait (dsymutil, pex);
307538fd1498Szrj }
307638fd1498Szrj 
307738fd1498Szrj static void
post_ld_pass(bool temp_file)307838fd1498Szrj post_ld_pass (bool temp_file) {
307938fd1498Szrj   if (!(temp_file && flag_idsym) && !flag_dsym)
308038fd1498Szrj     return;
308138fd1498Szrj 
308238fd1498Szrj   do_dsymutil (output_file);
308338fd1498Szrj }
308438fd1498Szrj #else
308538fd1498Szrj static void
process_args(int * argcp ATTRIBUTE_UNUSED,char ** argv ATTRIBUTE_UNUSED)308638fd1498Szrj process_args (int *argcp ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { }
post_ld_pass(bool temp_file ATTRIBUTE_UNUSED)308738fd1498Szrj static void post_ld_pass (bool temp_file ATTRIBUTE_UNUSED) { }
308838fd1498Szrj #endif
3089