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 (<o_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 (<o_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