X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gcc%2Fcollect2.c;h=497207281f3e8e76be8cf47a3435a57b96c43e0d;hb=4f67832ee1e9929d76bc05cd5daa1c2cf12d0dd0;hp=552aa85859eb7e9eb9a77cbfb44249d4e2da3d97;hpb=b352afbab2dcdf3b48b08e377f48d17109297c46;p=gcc.git diff --git a/gcc/collect2.c b/gcc/collect2.c index 552aa85859e..497207281f3 100644 --- a/gcc/collect2.c +++ b/gcc/collect2.c @@ -1,8 +1,6 @@ /* Collect static initialization info into data structures that can be traversed by C++ initialization and finalization routines. - Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011, 2012 - Free Software Foundation, Inc. + Copyright (C) 1992-2019 Free Software Foundation, Inc. Contributed by Chris Smith (csmith@convex.com). Heavily modified by Michael Meissner (meissner@cygnus.com), Per Bothner (bothner@cygnus.com), and John Gilmore (gnu@cygnus.com). @@ -32,6 +30,8 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "filenames.h" #include "file-find.h" +#include "simple-object.h" +#include "lto-section-names.h" /* TARGET_64BIT may be defined to use driver specific functionality. */ #undef TARGET_64BIT @@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see #include "collect2.h" #include "collect2-aix.h" +#include "collect-utils.h" #include "diagnostic.h" #include "demangle.h" #include "obstack.h" @@ -177,13 +178,13 @@ struct head int number; }; -bool vflag; /* true if -v or --version */ static int rflag; /* true if -r */ static int strip_flag; /* true if -s */ #ifdef COLLECT_EXPORT_LIST static int export_flag; /* true if -bE */ static int aix64_flag; /* true if -b64 */ static int aixrtl_flag; /* true if -brtl */ +static int aixlazy_flag; /* true if -blazy */ #endif enum lto_mode_d { @@ -193,15 +194,19 @@ enum lto_mode_d { }; /* Current LTO mode. */ +#ifdef ENABLE_LTO +static enum lto_mode_d lto_mode = LTO_MODE_WHOPR; +#else static enum lto_mode_d lto_mode = LTO_MODE_NONE; +#endif -bool debug; /* true if -debug */ bool helpflag; /* true if --help */ static int shared_obj; /* true if -shared */ +static int static_obj; /* true if -static */ -static const char *c_file; /* .c for constructor/destructor list. */ -static const char *o_file; /* .o for constructor/destructor list. */ +static char *c_file; /* .c for constructor/destructor list. */ +static char *o_file; /* .o for constructor/destructor list. */ #ifdef COLLECT_EXPORT_LIST static const char *export_file; /* .x for AIX export list. */ #endif @@ -217,6 +222,13 @@ static const char *strip_file_name; /* pathname of strip */ const char *c_file_name; /* pathname of gcc */ static char *initname, *fininame; /* names of init and fini funcs */ + +#ifdef TARGET_AIX_VERSION +static char *aix_shared_initname; +static char *aix_shared_fininame; /* init/fini names as per the scheme + described in config/rs6000/aix.h */ +#endif + static struct head constructors; /* list of constructors found */ static struct head destructors; /* list of destructors found */ #ifdef COLLECT_EXPORT_LIST @@ -224,8 +236,7 @@ static struct head exports; /* list of exported symbols */ #endif static struct head frame_tables; /* list of frame unwind info tables */ -static bool at_file_supplied; /* Whether to use @file arguments */ -static char *response_file; /* Name of any current response file */ +bool at_file_supplied; /* Whether to use @file arguments */ struct obstack temporary_obstack; char * temporary_firstobj; @@ -247,6 +258,7 @@ bool may_unlink_output_file = false; #ifdef COLLECT_EXPORT_LIST /* Lists to keep libraries to be scanned for global constructors/destructors. */ static struct head libs; /* list of libraries */ +static struct head static_libs; /* list of statically linked libraries */ static struct path_prefix cmdline_lib_dirs; /* directories specified with -L */ static struct path_prefix libpath_lib_dirs; /* directories in LIBPATH */ static struct path_prefix *libpaths[3] = {&cmdline_lib_dirs, @@ -274,22 +286,23 @@ static struct lto_object_list lto_objects; /* Special kinds of symbols that a name may denote. */ -typedef enum { +enum symkind { SYM_REGULAR = 0, /* nothing special */ SYM_CTOR = 1, /* constructor */ SYM_DTOR = 2, /* destructor */ SYM_INIT = 3, /* shared object routine that calls all the ctors */ SYM_FINI = 4, /* shared object routine that calls all the dtors */ - SYM_DWEH = 5 /* DWARF exception handling table */ -} symkind; + SYM_DWEH = 5, /* DWARF exception handling table */ + SYM_AIXI = 6, + SYM_AIXD = 7 +}; + +const char tool_name[] = "collect2"; static symkind is_ctor_dtor (const char *); static void handler (int); -static void do_wait (const char *, struct pex_obj *); -static void fork_execute (const char *, char **); -static void maybe_unlink (const char *); static void maybe_unlink_list (char **); static void add_to_list (struct head *, const char *); static int extract_init_priority (const char *); @@ -311,9 +324,7 @@ static void write_c_file_glob (FILE *, const char *); static void scan_libraries (const char *); #endif #ifdef COLLECT_EXPORT_LIST -#if 0 static int is_in_list (const char *, struct id *); -#endif static void write_aix_file (FILE *, struct id *); static char *resolve_lib_name (const char *); #endif @@ -324,13 +335,13 @@ static void process_args (int *argcp, char **argv); /* Enumerations describing which pass this is for scanning the program file ... */ -typedef enum { +enum scanpass { PASS_FIRST, /* without constructors */ PASS_OBJ, /* individual objects */ PASS_LIB, /* looking for shared libraries */ PASS_SECOND, /* with constructors linked in */ PASS_LTOINFO /* looking for objects with LTO info */ -} scanpass; +}; /* ... and which kinds of symbols are to be considered. */ @@ -342,6 +353,8 @@ enum scanfilter_masks { SCAN_INIT = 1 << SYM_INIT, SCAN_FINI = 1 << SYM_FINI, SCAN_DWEH = 1 << SYM_DWEH, + SCAN_AIXI = 1 << SYM_AIXI, + SCAN_AIXD = 1 << SYM_AIXD, SCAN_ALL = ~0 }; @@ -369,7 +382,7 @@ static void scan_prog_file (const char *, scanpass, scanfilter); /* Delete tempfiles and exit function. */ void -collect_exit (int status) +tool_cleanup (bool from_signal) { if (c_file != 0 && c_file[0]) maybe_unlink (c_file); @@ -387,37 +400,33 @@ collect_exit (int status) if (ldout != 0 && ldout[0]) { - dump_ld_file (ldout, stdout); + if (!from_signal) + dump_ld_file (ldout, stdout); maybe_unlink (ldout); } if (lderrout != 0 && lderrout[0]) { - dump_ld_file (lderrout, stderr); + if (!from_signal) + dump_ld_file (lderrout, stderr); maybe_unlink (lderrout); } +} - if (status != 0 && output_file != 0 && output_file[0]) - maybe_unlink (output_file); - - if (response_file) - maybe_unlink (response_file); - - exit (status); +static void +collect_atexit (void) +{ + tool_cleanup (false); } - -/* Notify user of a non-error. */ -void -notice (const char *cmsgid, ...) +static void +handler (int signo) { - va_list ap; + tool_cleanup (true); - va_start (ap, cmsgid); - vfprintf (stderr, _(cmsgid), ap); - va_end (ap); + signal (signo, SIG_DFL); + raise (signo); } - /* Notify user of a non-error, without translating the format string. */ void notice_translated (const char *cmsgid, ...) @@ -428,37 +437,6 @@ notice_translated (const char *cmsgid, ...) vfprintf (stderr, cmsgid, ap); va_end (ap); } - -static void -handler (int signo) -{ - if (c_file != 0 && c_file[0]) - maybe_unlink (c_file); - - if (o_file != 0 && o_file[0]) - maybe_unlink (o_file); - - if (ldout != 0 && ldout[0]) - maybe_unlink (ldout); - - if (lderrout != 0 && lderrout[0]) - maybe_unlink (lderrout); - -#ifdef COLLECT_EXPORT_LIST - if (export_file != 0 && export_file[0]) - maybe_unlink (export_file); -#endif - - if (lto_o_files) - maybe_unlink_list (lto_o_files); - - if (response_file) - maybe_unlink (response_file); - - signal (signo, SIG_DFL); - raise (signo); -} - int file_exists (const char *name) @@ -596,6 +574,10 @@ is_ctor_dtor (const char *s) { "GLOBAL__F_", sizeof ("GLOBAL__F_")-1, SYM_DWEH, 0 }, { "GLOBAL__FI_", sizeof ("GLOBAL__FI_")-1, SYM_INIT, 0 }, { "GLOBAL__FD_", sizeof ("GLOBAL__FD_")-1, SYM_FINI, 0 }, +#ifdef TARGET_AIX_VERSION + { "GLOBAL__AIXI_", sizeof ("GLOBAL__AIXI_")-1, SYM_AIXI, 0 }, + { "GLOBAL__AIXD_", sizeof ("GLOBAL__AIXD_")-1, SYM_AIXD, 0 }, +#endif { NULL, 0, SYM_REGULAR, 0 } }; @@ -609,7 +591,7 @@ is_ctor_dtor (const char *s) { if (ch == p->name[0] && (!p->two_underscores || ((s - orig_s) >= 2)) - && strncmp(s, p->name, p->len) == 0) + && strncmp (s, p->name, p->len) == 0) { return p->ret; } @@ -719,7 +701,8 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst, size_t num_files; if (!lto_wrapper) - fatal_error ("COLLECT_LTO_WRAPPER must be set"); + fatal_error (input_location, "environment variable " + "% must be set"); num_lto_c_args++; @@ -742,7 +725,8 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst, *lto_c_ptr = NULL; /* Run the LTO back end. */ - pex = collect_execute (prog, lto_c_argv, NULL, NULL, PEX_SEARCH); + pex = collect_execute (prog, lto_c_argv, NULL, NULL, PEX_SEARCH, + at_file_supplied); { int c; FILE *stream; @@ -780,11 +764,11 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst, do_wait (prog, pex); pex = NULL; - /* Compute memory needed for new LD arguments. At most number of original arguemtns + /* Compute memory needed for new LD arguments. At most number of original arguments plus number of partitions. */ for (lto_ld_argv_size = 0; lto_ld_argv[lto_ld_argv_size]; lto_ld_argv_size++) ; - out_lto_ld_argv = XCNEWVEC(char *, num_files + lto_ld_argv_size + 1); + out_lto_ld_argv = XCNEWVEC (char *, num_files + lto_ld_argv_size + 1); out_lto_ld_argv_size = 0; /* After running the LTO back end, we will relink, substituting @@ -822,8 +806,10 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst, /* Run the linker again, this time replacing the object files optimized by the LTO with the temporary file generated by the LTO. */ - fork_execute ("ld", out_lto_ld_argv); - post_ld_pass (true); + fork_execute ("ld", out_lto_ld_argv, HAVE_GNU_LD && at_file_supplied); + /* We assume that temp files were created, and therefore we need to take + that into account (maybe run dsymutil). */ + post_ld_pass (/*temp_file*/true); free (lto_ld_argv); maybe_unlink_list (lto_o_files); @@ -832,8 +818,35 @@ maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst, { /* Our caller is relying on us to do the link even though there is no LTO back end work to be done. */ - fork_execute ("ld", lto_ld_argv); - post_ld_pass (false); + fork_execute ("ld", lto_ld_argv, HAVE_GNU_LD && at_file_supplied); + /* No LTO objects were found, so no new temp file. */ + post_ld_pass (/*temp_file*/false); + } + else + post_ld_pass (false); /* No LTO objects were found, no temp file. */ +} +/* Entry point for linker invoation. Called from main in collect2.c. + LD_ARGV is an array of arguments for the linker. */ + +static void +do_link (char **ld_argv) +{ + struct pex_obj *pex; + const char *prog = "ld"; + pex = collect_execute (prog, ld_argv, NULL, NULL, + PEX_LAST | PEX_SEARCH, + HAVE_GNU_LD && at_file_supplied); + int ret = collect_wait (prog, pex); + if (ret) + { + error ("ld returned %d exit status", ret); + exit (ret); + } + else + { + /* We have just successfully produced an output file, so assume that we + may unlink it if need be for now on. */ + may_unlink_output_file = true; } } @@ -848,6 +861,7 @@ main (int argc, char **argv) USE_PLUGIN_LD, USE_GOLD_LD, USE_BFD_LD, + USE_LLD_LD, USE_LD_MAX } selected_linker = USE_DEFAULT_LD; static const char *const ld_suffixes[USE_LD_MAX] = @@ -855,7 +869,8 @@ main (int argc, char **argv) "ld", PLUGIN_LD_SUFFIX, "ld.gold", - "ld.bfd" + "ld.bfd", + "ld.lld" }; static const char *const real_ld_suffix = "real-ld"; static const char *const collect_ld_suffix = "collect-ld"; @@ -928,6 +943,9 @@ main (int argc, char **argv) int first_file; int num_c_args; char **old_argv; +#ifdef COLLECT_EXPORT_LIST + bool is_static = false; +#endif int i; for (i = 0; i < USE_LD_MAX; i++) @@ -979,6 +997,9 @@ main (int argc, char **argv) diagnostic_initialize (global_dc, 0); + if (atexit (collect_atexit) != 0) + fatal_error (input_location, "atexit failed"); + /* Do not invoke xcalloc before this point, since locale needs to be set first, in case a diagnostic is issued. */ @@ -990,13 +1011,21 @@ main (int argc, char **argv) object = CONST_CAST2 (const char **, char **, object_lst); #ifdef DEBUG - debug = 1; + debug = true; #endif - /* Parse command line early for instances of -debug. This allows - the debug flag to be set before functions like find_a_file() - are called. We also look for the -flto or -flto-partition=none flag to know - what LTO mode we are in. */ + save_temps = false; + verbose = false; + +#ifndef DEFAULT_A_OUT_NAME + output_file = "a.out"; +#else + output_file = DEFAULT_A_OUT_NAME; +#endif + + /* Parse command line / environment for flags we want early. + This allows the debug flag to be set before functions like find_a_file() + are called. */ { bool no_partition = false; @@ -1004,17 +1033,11 @@ main (int argc, char **argv) { if (! strcmp (argv[i], "-debug")) debug = true; - else if (! strcmp (argv[i], "-flto-partition=none")) - no_partition = true; - else if ((! strncmp (argv[i], "-flto=", 6) - || ! strcmp (argv[i], "-flto")) && ! use_plugin) - lto_mode = LTO_MODE_WHOPR; else if (!strncmp (argv[i], "-fno-lto", 8)) lto_mode = LTO_MODE_NONE; else if (! strcmp (argv[i], "-plugin")) { use_plugin = true; - lto_mode = LTO_MODE_NONE; if (selected_linker == USE_DEFAULT_LD) selected_linker = USE_PLUGIN_LD; } @@ -1022,50 +1045,72 @@ main (int argc, char **argv) selected_linker = USE_BFD_LD; else if (strcmp (argv[i], "-fuse-ld=gold") == 0) selected_linker = USE_GOLD_LD; + else if (strcmp (argv[i], "-fuse-ld=lld") == 0) + selected_linker = USE_LLD_LD; + else if (strncmp (argv[i], "-o", 2) == 0) + { + /* Parse the output filename if it's given so that we can make + meaningful temp filenames. */ + if (argv[i][2] == '\0') + output_file = argv[i+1]; + else + output_file = &argv[i][2]; + } #ifdef COLLECT_EXPORT_LIST - /* since -brtl, -bexport, -b64 are not position dependent - also check for them here */ - if ((argv[i][0] == '-') && (argv[i][1] == 'b')) - { - arg = argv[i]; - /* We want to disable automatic exports on AIX when user - explicitly puts an export list in command line */ - if (arg[2] == 'E' || strncmp (&arg[2], "export", 6) == 0) - export_flag = 1; - else if (arg[2] == '6' && arg[3] == '4') - aix64_flag = 1; - else if (arg[2] == 'r' && arg[3] == 't' && arg[4] == 'l') - aixrtl_flag = 1; - } + /* These flags are position independent, although their order + is important - subsequent flags override earlier ones. */ + else if (strcmp (argv[i], "-b64") == 0) + aix64_flag = 1; + /* -bexport:filename always needs the :filename */ + else if (strncmp (argv[i], "-bE:", 4) == 0 + || strncmp (argv[i], "-bexport:", 9) == 0) + export_flag = 1; + else if (strcmp (argv[i], "-brtl") == 0 + || strcmp (argv[i], "-bsvr4") == 0 + || strcmp (argv[i], "-G") == 0) + aixrtl_flag = 1; + else if (strcmp (argv[i], "-bnortl") == 0) + aixrtl_flag = 0; + else if (strcmp (argv[i], "-blazy") == 0) + aixlazy_flag = 1; #endif } - vflag = debug; - find_file_set_debug (debug); - if (no_partition && lto_mode == LTO_MODE_WHOPR) - lto_mode = LTO_MODE_LTO; - } - -#ifndef DEFAULT_A_OUT_NAME - output_file = "a.out"; -#else - output_file = DEFAULT_A_OUT_NAME; -#endif - obstack_begin (&temporary_obstack, 0); - temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0); + obstack_begin (&temporary_obstack, 0); + temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0); #ifndef HAVE_LD_DEMANGLE current_demangling_style = auto_demangling; #endif - p = getenv ("COLLECT_GCC_OPTIONS"); - while (p && *p) - { - const char *q = extract_string (&p); - if (*q == '-' && (q[1] == 'm' || q[1] == 'f')) - num_c_args++; + + /* Now pick up any flags we want early from COLLECT_GCC_OPTIONS + The LTO options are passed here as are other options that might + be unsuitable for ld (e.g. -save-temps). */ + p = getenv ("COLLECT_GCC_OPTIONS"); + while (p && *p) + { + const char *q = extract_string (&p); + if (*q == '-' && (q[1] == 'm' || q[1] == 'f')) + num_c_args++; + if (strncmp (q, "-flto-partition=none", 20) == 0) + no_partition = true; + else if (strncmp (q, "-fno-lto", 8) == 0) + lto_mode = LTO_MODE_NONE; + else if (strncmp (q, "-save-temps", 11) == 0) + /* FIXME: Honour =obj. */ + save_temps = true; } - obstack_free (&temporary_obstack, temporary_firstobj); + obstack_free (&temporary_obstack, temporary_firstobj); + + verbose = verbose || debug; + save_temps = save_temps || debug; + find_file_set_debug (debug); + if (use_plugin) + lto_mode = LTO_MODE_NONE; + if (no_partition && lto_mode == LTO_MODE_WHOPR) + lto_mode = LTO_MODE_LTO; + } /* -fno-profile-arcs -fno-test-coverage -fno-branch-probabilities -fno-exceptions -w -fno-whole-program */ @@ -1075,7 +1120,7 @@ main (int argc, char **argv) c_ptr = CONST_CAST2 (const char **, char **, c_argv); if (argc < 2) - fatal_error ("no arguments"); + fatal_error (input_location, "no arguments"); #ifdef SIGQUIT if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) @@ -1107,60 +1152,89 @@ main (int argc, char **argv) /* Maybe we know the right file to use (if not cross). */ ld_file_name = 0; #ifdef DEFAULT_LINKER - if (access (DEFAULT_LINKER, X_OK) == 0) + if (selected_linker == USE_BFD_LD || selected_linker == USE_GOLD_LD || + selected_linker == USE_LLD_LD) + { + char *linker_name; +# ifdef HOST_EXECUTABLE_SUFFIX + int len = (sizeof (DEFAULT_LINKER) + - sizeof (HOST_EXECUTABLE_SUFFIX)); + linker_name = NULL; + if (len > 0) + { + char *default_linker = xstrdup (DEFAULT_LINKER); + /* Strip HOST_EXECUTABLE_SUFFIX if DEFAULT_LINKER contains + HOST_EXECUTABLE_SUFFIX. */ + if (! strcmp (&default_linker[len], HOST_EXECUTABLE_SUFFIX)) + { + default_linker[len] = '\0'; + linker_name = concat (default_linker, + &ld_suffixes[selected_linker][2], + HOST_EXECUTABLE_SUFFIX, NULL); + } + } + if (linker_name == NULL) +# endif + linker_name = concat (DEFAULT_LINKER, + &ld_suffixes[selected_linker][2], + NULL); + if (access (linker_name, X_OK) == 0) + ld_file_name = linker_name; + } + if (ld_file_name == 0 && access (DEFAULT_LINKER, X_OK) == 0) ld_file_name = DEFAULT_LINKER; if (ld_file_name == 0) #endif #ifdef REAL_LD_FILE_NAME - ld_file_name = find_a_file (&path, REAL_LD_FILE_NAME); + ld_file_name = find_a_file (&path, REAL_LD_FILE_NAME, X_OK); if (ld_file_name == 0) #endif /* Search the (target-specific) compiler dirs for ld'. */ - ld_file_name = find_a_file (&cpath, real_ld_suffix); + ld_file_name = find_a_file (&cpath, real_ld_suffix, X_OK); /* Likewise for `collect-ld'. */ if (ld_file_name == 0) { - ld_file_name = find_a_file (&cpath, collect_ld_suffix); + ld_file_name = find_a_file (&cpath, collect_ld_suffix, X_OK); use_collect_ld = ld_file_name != 0; } /* Search the compiler directories for `ld'. We have protection against recursive calls in find_a_file. */ if (ld_file_name == 0) - ld_file_name = find_a_file (&cpath, ld_suffixes[selected_linker]); + ld_file_name = find_a_file (&cpath, ld_suffixes[selected_linker], X_OK); /* Search the ordinary system bin directories for `ld' (if native linking) or `TARGET-ld' (if cross). */ if (ld_file_name == 0) - ld_file_name = find_a_file (&path, full_ld_suffixes[selected_linker]); + ld_file_name = find_a_file (&path, full_ld_suffixes[selected_linker], X_OK); #ifdef REAL_NM_FILE_NAME - nm_file_name = find_a_file (&path, REAL_NM_FILE_NAME); + nm_file_name = find_a_file (&path, REAL_NM_FILE_NAME, X_OK); if (nm_file_name == 0) #endif - nm_file_name = find_a_file (&cpath, gnm_suffix); + nm_file_name = find_a_file (&cpath, gnm_suffix, X_OK); if (nm_file_name == 0) - nm_file_name = find_a_file (&path, full_gnm_suffix); + nm_file_name = find_a_file (&path, full_gnm_suffix, X_OK); if (nm_file_name == 0) - nm_file_name = find_a_file (&cpath, nm_suffix); + nm_file_name = find_a_file (&cpath, nm_suffix, X_OK); if (nm_file_name == 0) - nm_file_name = find_a_file (&path, full_nm_suffix); + nm_file_name = find_a_file (&path, full_nm_suffix, X_OK); #ifdef LDD_SUFFIX - ldd_file_name = find_a_file (&cpath, ldd_suffix); + ldd_file_name = find_a_file (&cpath, ldd_suffix, X_OK); if (ldd_file_name == 0) - ldd_file_name = find_a_file (&path, full_ldd_suffix); + ldd_file_name = find_a_file (&path, full_ldd_suffix, X_OK); #endif #ifdef REAL_STRIP_FILE_NAME - strip_file_name = find_a_file (&path, REAL_STRIP_FILE_NAME); + strip_file_name = find_a_file (&path, REAL_STRIP_FILE_NAME, X_OK); if (strip_file_name == 0) #endif - strip_file_name = find_a_file (&cpath, gstrip_suffix); + strip_file_name = find_a_file (&cpath, gstrip_suffix, X_OK); if (strip_file_name == 0) - strip_file_name = find_a_file (&path, full_gstrip_suffix); + strip_file_name = find_a_file (&path, full_gstrip_suffix, X_OK); if (strip_file_name == 0) - strip_file_name = find_a_file (&cpath, strip_suffix); + strip_file_name = find_a_file (&cpath, strip_suffix, X_OK); if (strip_file_name == 0) - strip_file_name = find_a_file (&path, full_strip_suffix); + strip_file_name = find_a_file (&path, full_strip_suffix, X_OK); /* Determine the full path name of the C compiler to use. */ c_file_name = getenv ("COLLECT_GCC"); @@ -1173,12 +1247,12 @@ main (int argc, char **argv) #endif } - p = find_a_file (&cpath, c_file_name); + p = find_a_file (&cpath, c_file_name, X_OK); /* Here it should be safe to use the system search path since we should have already qualified the name of the compiler when it is needed. */ if (p == 0) - p = find_a_file (&path, c_file_name); + p = find_a_file (&path, c_file_name, X_OK); if (p) c_file_name = p; @@ -1186,13 +1260,31 @@ main (int argc, char **argv) *ld1++ = *ld2++ = ld_file_name; /* Make temp file names. */ - c_file = make_temp_file (".c"); - o_file = make_temp_file (".o"); + if (save_temps) + { + c_file = (char *) xmalloc (strlen (output_file) + + sizeof (".cdtor.c") + 1); + strcpy (c_file, output_file); + strcat (c_file, ".cdtor.c"); + o_file = (char *) xmalloc (strlen (output_file) + + sizeof (".cdtor.o") + 1); + strcpy (o_file, output_file); + strcat (o_file, ".cdtor.o"); + } + else + { + c_file = make_temp_file (".cdtor.c"); + o_file = make_temp_file (".cdtor.o"); + } #ifdef COLLECT_EXPORT_LIST export_file = make_temp_file (".x"); #endif - ldout = make_temp_file (".ld"); - lderrout = make_temp_file (".le"); + if (!debug) + { + ldout = make_temp_file (".ld"); + lderrout = make_temp_file (".le"); + } + /* Build the command line to compile the ctor/dtor list. */ *c_ptr++ = c_file_name; *c_ptr++ = "-x"; *c_ptr++ = "c"; @@ -1224,6 +1316,8 @@ main (int argc, char **argv) *c_ptr++ = xstrdup (q); if (strcmp (q, "-shared") == 0) shared_obj = 1; + if (strcmp (q, "-static") == 0) + static_obj = 1; if (*q == '-' && q[1] == 'B') { *c_ptr++ = xstrdup (q); @@ -1252,6 +1346,9 @@ main (int argc, char **argv) /* Parse arguments. Remember output file spec, pass the rest to ld. */ /* After the first file, put in the c++ rt0. */ +#ifdef COLLECT_EXPORT_LIST + is_static = static_obj; +#endif first_file = 1; while ((arg = *++argv) != (char *) 0) { @@ -1290,7 +1387,13 @@ main (int argc, char **argv) else if (!use_collect_ld && strncmp (arg, "-fuse-ld=", 9) == 0) { - /* Do not pass -fuse-ld={bfd|gold} to the linker. */ + /* Do not pass -fuse-ld={bfd|gold|lld} to the linker. */ + ld1--; + ld2--; + } + else if (strncmp (arg, "-fno-lto", 8) == 0) + { + /* Do not pass -fno-lto to the linker. */ ld1--; ld2--; } @@ -1318,7 +1421,8 @@ main (int argc, char **argv) stream = fopen (list_filename, "r"); if (stream == NULL) - fatal_error ("can't open %s: %m", list_filename); + fatal_error (input_location, "cannot open %s: %m", + list_filename); while (fgets (buf, sizeof buf, stream) != NULL) { @@ -1350,6 +1454,18 @@ main (int argc, char **argv) #endif break; +#ifdef COLLECT_EXPORT_LIST + case 'b': + if (!strcmp (arg, "-bstatic")) + { + is_static = true; + } + else if (!strcmp (arg, "-bdynamic") || !strcmp (arg, "-bshared")) + { + is_static = false; + } + break; +#endif case 'l': if (first_file) { @@ -1366,6 +1482,8 @@ main (int argc, char **argv) /* Saving a full library name. */ add_to_list (&libs, s); + if (is_static) + add_to_list (&static_libs, s); } #endif break; @@ -1402,7 +1520,7 @@ main (int argc, char **argv) case 'v': if (arg[2] == '\0') - vflag = true; + verbose = true; break; case '-': @@ -1423,7 +1541,7 @@ main (int argc, char **argv) enum demangling_styles style = cplus_demangle_name_to_style (arg+11); if (style == unknown_demangling) - error ("unknown demangling style '%s'", arg+11); + error ("unknown demangling style %qs", arg+11); else current_demangling_style = style; } @@ -1434,7 +1552,7 @@ main (int argc, char **argv) else if (strncmp (arg, "--sysroot=", 10) == 0) target_system_root = arg + 10; else if (strcmp (arg, "--version") == 0) - vflag = true; + verbose = true; else if (strcmp (arg, "--help") == 0) helpflag = true; break; @@ -1466,6 +1584,8 @@ main (int argc, char **argv) { /* Saving a full library name. */ add_to_list (&libs, arg); + if (is_static) + add_to_list (&static_libs, arg); } #endif } @@ -1477,6 +1597,8 @@ main (int argc, char **argv) { fprintf (stderr, "List of libraries:\n"); dump_list (stderr, "\t", libs.first); + fprintf (stderr, "List of statically linked libraries:\n"); + dump_list (stderr, "\t", static_libs.first); } /* The AIX linker will discard static constructors in object files if @@ -1501,9 +1623,11 @@ main (int argc, char **argv) this_filter &= ~SCAN_DWEH; #endif + /* Scan object files. */ while (export_object_lst < object) scan_prog_file (*export_object_lst++, PASS_OBJ, this_filter); + /* Scan libraries. */ for (; list; list = list->next) scan_prog_file (list->name, PASS_FIRST, this_filter); @@ -1519,17 +1643,17 @@ main (int argc, char **argv) exportf = fopen (export_file, "w"); if (exportf == (FILE *) 0) - fatal_error ("fopen %s: %m", export_file); + fatal_error (input_location, "fopen %s: %m", export_file); write_aix_file (exportf, exports.first); if (fclose (exportf)) - fatal_error ("fclose %s: %m", export_file); + fatal_error (input_location, "fclose %s: %m", export_file); } #endif *c_ptr++ = c_file; *c_ptr = *ld1 = *object = (char *) 0; - if (vflag) + if (verbose) notice ("collect2 version %s\n", version_string); if (helpflag) @@ -1541,7 +1665,7 @@ main (int argc, char **argv) printf (" --help Display this information\n"); printf (" -v, --version Display this program's version number\n"); printf ("\n"); - printf ("Overview: http://gcc.gnu.org/onlinedocs/gccint/Collect2.html\n"); + printf ("Overview: https://gcc.gnu.org/onlinedocs/gccint/Collect2.html\n"); printf ("Report bugs: %s\n", bug_report_url); printf ("\n"); } @@ -1604,7 +1728,7 @@ main (int argc, char **argv) functions from precise cross reference insertions by the compiler. */ if (early_exit || ld1_filter != SCAN_NOTHING) - do_tlink (ld1_argv, object_lst); + do_link (ld1_argv); if (early_exit) { @@ -1616,10 +1740,8 @@ main (int argc, char **argv) if (lto_mode != LTO_MODE_NONE) maybe_run_lto_and_relink (ld1_argv, object_lst, object, false); else - post_ld_pass (false); + post_ld_pass (/*temp_file*/false); - maybe_unlink (c_file); - maybe_unlink (o_file); return 0; } } @@ -1645,9 +1767,9 @@ main (int argc, char **argv) "%d destructors found\n", destructors.number), destructors.number); - notice_translated (ngettext("%d frame table found\n", - "%d frame tables found\n", - frame_tables.number), + notice_translated (ngettext ("%d frame table found\n", + "%d frame tables found\n", + frame_tables.number), frame_tables.number); } @@ -1664,10 +1786,10 @@ main (int argc, char **argv) #endif ) { - /* Do tlink without additional code generation now if we didn't + /* Do link without additional code generation now if we didn't do it earlier for scanning purposes. */ if (ld1_filter == SCAN_NOTHING) - do_tlink (ld1_argv, object_lst); + do_link (ld1_argv); if (lto_mode) maybe_run_lto_and_relink (ld1_argv, object_lst, object, false); @@ -1682,13 +1804,13 @@ main (int argc, char **argv) strip_argv[0] = strip_file_name; strip_argv[1] = output_file; strip_argv[2] = (char *) 0; - fork_execute ("strip", real_strip_argv); + fork_execute ("strip", real_strip_argv, false); } #ifdef COLLECT_EXPORT_LIST maybe_unlink (export_file); #endif - post_ld_pass (false); + post_ld_pass (/*temp_file*/false); maybe_unlink (c_file); maybe_unlink (o_file); @@ -1699,15 +1821,15 @@ main (int argc, char **argv) sort_ids (&constructors); sort_ids (&destructors); - maybe_unlink(output_file); + maybe_unlink (output_file); outf = fopen (c_file, "w"); if (outf == (FILE *) 0) - fatal_error ("fopen %s: %m", c_file); + fatal_error (input_location, "fopen %s: %m", c_file); write_c_file (outf, c_file); if (fclose (outf)) - fatal_error ("fclose %s: %m", c_file); + fatal_error (input_location, "fclose %s: %m", c_file); /* Tell the linker that we have initializer and finalizer functions. */ #ifdef LD_INIT_SWITCH @@ -1729,6 +1851,11 @@ main (int argc, char **argv) if (! exports.first) *ld2++ = concat ("-bE:", export_file, NULL); +#ifdef TARGET_AIX_VERSION + add_to_list (&exports, aix_shared_initname); + add_to_list (&exports, aix_shared_fininame); +#endif + #ifndef LD_INIT_SWITCH add_to_list (&exports, initname); add_to_list (&exports, fininame); @@ -1737,10 +1864,10 @@ main (int argc, char **argv) #endif exportf = fopen (export_file, "w"); if (exportf == (FILE *) 0) - fatal_error ("fopen %s: %m", export_file); + fatal_error (input_location, "fopen %s: %m", export_file); write_aix_file (exportf, exports.first); if (fclose (exportf)) - fatal_error ("fclose %s: %m", export_file); + fatal_error (input_location, "fclose %s: %m", export_file); } #endif @@ -1763,21 +1890,21 @@ main (int argc, char **argv) /* Assemble the constructor and destructor tables. Link the tables in with the rest of the program. */ - fork_execute ("gcc", c_argv); + fork_execute ("gcc", c_argv, at_file_supplied); #ifdef COLLECT_EXPORT_LIST - /* On AIX we must call tlink because of possible templates resolution. */ - do_tlink (ld2_argv, object_lst); + /* On AIX we must call link because of possible templates resolution. */ + do_link (ld2_argv); if (lto_mode) maybe_run_lto_and_relink (ld2_argv, object_lst, object, false); #else - /* Otherwise, simply call ld because tlink is already done. */ + /* Otherwise, simply call ld because link is already done. */ if (lto_mode) maybe_run_lto_and_relink (ld2_argv, object_lst, object, true); else { - fork_execute ("ld", ld2_argv); - post_ld_pass (false); + fork_execute ("ld", ld2_argv, HAVE_GNU_LD && at_file_supplied); + post_ld_pass (/*temp_file*/false); } /* Let scan_prog_file do any final mods (OSF/rose needs this for @@ -1795,169 +1922,17 @@ main (int argc, char **argv) return 0; } - -/* Wait for a process to finish, and exit if a nonzero status is found. */ - -int -collect_wait (const char *prog, struct pex_obj *pex) -{ - int status; - - if (!pex_get_status (pex, 1, &status)) - fatal_error ("can't get program status: %m"); - pex_free (pex); - - if (status) - { - if (WIFSIGNALED (status)) - { - int sig = WTERMSIG (status); - error ("%s terminated with signal %d [%s]%s", - prog, sig, strsignal(sig), - WCOREDUMP(status) ? ", core dumped" : ""); - collect_exit (FATAL_EXIT_CODE); - } - - if (WIFEXITED (status)) - return WEXITSTATUS (status); - } - return 0; -} - -static void -do_wait (const char *prog, struct pex_obj *pex) -{ - int ret = collect_wait (prog, pex); - if (ret != 0) - { - error ("%s returned %d exit status", prog, ret); - collect_exit (ret); - } - - if (response_file) - { - unlink (response_file); - response_file = NULL; - } -} - - -/* Execute a program, and wait for the reply. */ - -struct pex_obj * -collect_execute (const char *prog, char **argv, const char *outname, - const char *errname, int flags) -{ - struct pex_obj *pex; - const char *errmsg; - int err; - char *response_arg = NULL; - char *response_argv[3] ATTRIBUTE_UNUSED; - - if (HAVE_GNU_LD && at_file_supplied && argv[0] != NULL) - { - /* If using @file arguments, create a temporary file and put the - contents of argv into it. Then change argv to an array corresponding - to a single argument @FILE, where FILE is the temporary filename. */ - - char **current_argv = argv + 1; - char *argv0 = argv[0]; - int status; - FILE *f; - - /* Note: we assume argv contains at least one element; this is - checked above. */ - - response_file = make_temp_file (""); - - f = fopen (response_file, "w"); - - if (f == NULL) - fatal_error ("could not open response file %s", response_file); - - status = writeargv (current_argv, f); - - if (status) - fatal_error ("could not write to response file %s", response_file); - - status = fclose (f); - - if (EOF == status) - fatal_error ("could not close response file %s", response_file); - - response_arg = concat ("@", response_file, NULL); - response_argv[0] = argv0; - response_argv[1] = response_arg; - response_argv[2] = NULL; - - argv = response_argv; - } - - if (vflag || debug) - { - char **p_argv; - const char *str; - - if (argv[0]) - fprintf (stderr, "%s", argv[0]); - else - notice ("[cannot find %s]", prog); - - for (p_argv = &argv[1]; (str = *p_argv) != (char *) 0; p_argv++) - fprintf (stderr, " %s", str); - - fprintf (stderr, "\n"); - } - - fflush (stdout); - fflush (stderr); - - /* If we cannot find a program we need, complain error. Do this here - since we might not end up needing something that we could not find. */ - - if (argv[0] == 0) - fatal_error ("cannot find '%s'", prog); - - pex = pex_init (0, "collect2", NULL); - if (pex == NULL) - fatal_error ("pex_init failed: %m"); - - errmsg = pex_run (pex, flags, argv[0], argv, outname, - errname, &err); - if (errmsg != NULL) - { - if (err != 0) - { - errno = err; - fatal_error ("%s: %m", _(errmsg)); - } - else - fatal_error (errmsg); - } - - free (response_arg); - - return pex; -} - -static void -fork_execute (const char *prog, char **argv) -{ - struct pex_obj *pex; - - pex = collect_execute (prog, argv, NULL, NULL, PEX_LAST | PEX_SEARCH); - do_wait (prog, pex); -} /* Unlink FILE unless we are debugging or this is the output_file and we may not unlink it. */ -static void +void maybe_unlink (const char *file) { - if (debug) + if (save_temps && file_exists (file)) { - notice ("[Leaving %s]\n", file); + if (verbose) + notice ("[Leaving %s]\n", file); return; } @@ -2021,6 +1996,19 @@ extract_init_priority (const char *name) { int pos = 0, pri; +#ifdef TARGET_AIX_VERSION + /* Run dependent module initializers before any constructors in this + module. */ + switch (is_ctor_dtor (name)) + { + case SYM_AIXI: + case SYM_AIXD: + return INT_MIN; + default: + break; + } +#endif + while (name[pos] == '_') ++pos; pos += 10; /* strlen ("GLOBAL__X_") */ @@ -2086,7 +2074,6 @@ write_list (FILE *stream, const char *prefix, struct id *list) #ifdef COLLECT_EXPORT_LIST /* This function is really used only on AIX, but may be useful. */ -#if 0 static int is_in_list (const char *prefix, struct id *list) { @@ -2097,7 +2084,6 @@ is_in_list (const char *prefix, struct id *list) } return 0; } -#endif #endif /* COLLECT_EXPORT_LIST */ /* Added for debugging purpose. */ @@ -2181,11 +2167,22 @@ write_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED) initname = concat ("_GLOBAL__FI_", prefix, NULL); fininame = concat ("_GLOBAL__FD_", prefix, NULL); +#ifdef TARGET_AIX_VERSION + aix_shared_initname = concat ("_GLOBAL__AIXI_", prefix, NULL); + aix_shared_fininame = concat ("_GLOBAL__AIXD_", prefix, NULL); +#endif free (prefix); /* Write the tables as C code. */ + /* This count variable is used to prevent multiple calls to the + constructors/destructors. + This guard against multiple calls is important on AIX as the initfini + functions are deliberately invoked multiple times as part of the + mechanisms GCC uses to order constructors across different dependent + shared libraries (see config/rs6000/aix.h). + */ fprintf (stream, "static int count;\n"); fprintf (stream, "typedef void entry_pt();\n"); write_list_with_asm (stream, "extern entry_pt ", constructors.first); @@ -2208,12 +2205,23 @@ write_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED) fprintf (stream, " struct object *next;\n"); fprintf (stream, "};\n"); + fprintf (stream, "extern void __register_frame_info_table_bases (void *, struct object *, void *tbase, void *dbase);\n"); fprintf (stream, "extern void __register_frame_info_table (void *, struct object *);\n"); fprintf (stream, "extern void *__deregister_frame_info (void *);\n"); +#ifdef TARGET_AIX_VERSION + fprintf (stream, "extern void *__gcc_unwind_dbase;\n"); +#endif fprintf (stream, "static void reg_frame () {\n"); fprintf (stream, "\tstatic struct object ob;\n"); +#ifdef TARGET_AIX_VERSION + /* Use __gcc_unwind_dbase as the base address for data on AIX. + This might not be the start of the segment, signed offsets assumed. + */ + fprintf (stream, "\t__register_frame_info_table_bases (frame_table, &ob, (void *)0, &__gcc_unwind_dbase);\n"); +#else fprintf (stream, "\t__register_frame_info_table (frame_table, &ob);\n"); +#endif fprintf (stream, "\t}\n"); fprintf (stream, "static void dereg_frame () {\n"); @@ -2256,8 +2264,8 @@ write_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED) if (shared_obj) { - COLLECT_SHARED_INIT_FUNC(stream, initname); - COLLECT_SHARED_FINI_FUNC(stream, fininame); + COLLECT_SHARED_INIT_FUNC (stream, initname); + COLLECT_SHARED_FINI_FUNC (stream, fininame); } } @@ -2354,38 +2362,52 @@ write_aix_file (FILE *stream, struct id *list) /* Check to make sure the file is an LTO object file. */ +static int +has_lto_section (void *data, const char *name ATTRIBUTE_UNUSED, + off_t offset ATTRIBUTE_UNUSED, + off_t length ATTRIBUTE_UNUSED) +{ + int *found = (int *) data; + + if (strncmp (name, LTO_SECTION_NAME_PREFIX, + sizeof (LTO_SECTION_NAME_PREFIX) - 1) != 0) + { + if (strncmp (name, OFFLOAD_SECTION_NAME_PREFIX, + sizeof (OFFLOAD_SECTION_NAME_PREFIX) - 1) != 0) + return 1; + } + + *found = 1; + + /* Stop iteration. */ + return 0; +} + static bool -maybe_lto_object_file (const char *prog_name) +is_lto_object_file (const char *prog_name) { - FILE *f; - unsigned char buf[4]; - int i; + const char *errmsg; + int err; + int found = 0; + off_t inoff = 0; + int infd = open (prog_name, O_RDONLY | O_BINARY); - static unsigned char elfmagic[4] = { 0x7f, 'E', 'L', 'F' }; - static unsigned char coffmagic[2] = { 0x4c, 0x01 }; - static unsigned char coffmagic_x64[2] = { 0x64, 0x86 }; - static unsigned char machomagic[4][4] = { - { 0xcf, 0xfa, 0xed, 0xfe }, - { 0xce, 0xfa, 0xed, 0xfe }, - { 0xfe, 0xed, 0xfa, 0xcf }, - { 0xfe, 0xed, 0xfa, 0xce } - }; + if (infd == -1) + return false; - f = fopen (prog_name, "rb"); - if (f == NULL) + simple_object_read *inobj = simple_object_start_read (infd, inoff, + LTO_SEGMENT_NAME, + &errmsg, &err); + if (!inobj) return false; - if (fread (buf, sizeof (buf), 1, f) != 1) - buf[0] = 0; - fclose (f); - if (memcmp (buf, elfmagic, sizeof (elfmagic)) == 0 - || memcmp (buf, coffmagic, sizeof (coffmagic)) == 0 - || memcmp (buf, coffmagic_x64, sizeof (coffmagic_x64)) == 0) + errmsg = simple_object_find_sections (inobj, has_lto_section, + (void *) &found, &err); + if (! errmsg && found) return true; - for (i = 0; i < 4; i++) - if (memcmp (buf, machomagic[i], sizeof (machomagic[i])) == 0) - return true; + if (errmsg) + fatal_error (0, "%s: %s", errmsg, xstrerror (err)); return false; } @@ -2408,7 +2430,6 @@ scan_prog_file (const char *prog_name, scanpass which_pass, int err; char *p, buf[1024]; FILE *inf; - int found_lto = 0; if (which_pass == PASS_SECOND) return; @@ -2416,12 +2437,17 @@ scan_prog_file (const char *prog_name, scanpass which_pass, /* LTO objects must be in a known format. This check prevents us from accepting an archive containing LTO objects, which gcc cannot currently handle. */ - if (which_pass == PASS_LTOINFO && !maybe_lto_object_file (prog_name)) - return; + if (which_pass == PASS_LTOINFO) + { + if(is_lto_object_file (prog_name)) { + add_lto_object (<o_objects, prog_name); + } + return; + } /* If we do not have an `nm', complain. */ if (nm_file_name == 0) - fatal_error ("cannot find 'nm'"); + fatal_error (input_location, "cannot find %"); nm_argv[argc++] = nm_file_name; if (NM_FLAGS[0] != '\0') @@ -2431,7 +2457,7 @@ scan_prog_file (const char *prog_name, scanpass which_pass, nm_argv[argc++] = (char *) 0; /* Trace if needed. */ - if (vflag) + if (verbose) { const char **p_argv; const char *str; @@ -2447,7 +2473,7 @@ scan_prog_file (const char *prog_name, scanpass which_pass, pex = pex_init (PEX_USE_PIPES, "collect2", NULL); if (pex == NULL) - fatal_error ("pex_init failed: %m"); + fatal_error (input_location, "% failed: %m"); errmsg = pex_run (pex, 0, nm_file_name, real_nm_argv, NULL, HOST_BIT_BUCKET, &err); @@ -2456,10 +2482,10 @@ scan_prog_file (const char *prog_name, scanpass which_pass, if (err != 0) { errno = err; - fatal_error ("%s: %m", _(errmsg)); + fatal_error (input_location, "%s: %m", _(errmsg)); } else - fatal_error (errmsg); + fatal_error (input_location, errmsg); } int_handler = (void (*) (int)) signal (SIGINT, SIG_IGN); @@ -2469,15 +2495,10 @@ scan_prog_file (const char *prog_name, scanpass which_pass, inf = pex_read_output (pex, 0); if (inf == NULL) - fatal_error ("can't open nm output: %m"); + fatal_error (input_location, "cannot open nm output: %m"); if (debug) - { - if (which_pass == PASS_LTOINFO) - fprintf (stderr, "\nnm output with LTO info marker symbol.\n"); - else - fprintf (stderr, "\nnm output with constructors/destructors.\n"); - } + fprintf (stderr, "\nnm output with constructors/destructors.\n"); /* Read each line of nm output. */ while (fgets (buf, sizeof buf, inf) != (char *) 0) @@ -2488,30 +2509,6 @@ scan_prog_file (const char *prog_name, scanpass which_pass, if (debug) fprintf (stderr, "\t%s\n", buf); - if (which_pass == PASS_LTOINFO) - { - if (found_lto) - continue; - - /* Look for the LTO info marker symbol, and add filename to - the LTO objects list if found. */ - for (p = buf; (ch = *p) != '\0' && ch != '\n'; p++) - if (ch == ' ' && p[1] == '_' && p[2] == '_' - && (strncmp (p + (p[3] == '_' ? 2 : 1), "__gnu_lto_v1", 12) == 0) - && ISSPACE (p[p[3] == '_' ? 14 : 13])) - { - add_lto_object (<o_objects, prog_name); - - /* We need to read all the input, so we can't just - return here. But we can avoid useless work. */ - found_lto = 1; - - break; - } - - continue; - } - /* If it contains a constructor or destructor name, add the name to the appropriate list unless this is a kind of symbol we're not supposed to even consider. */ @@ -2532,6 +2529,7 @@ scan_prog_file (const char *prog_name, scanpass which_pass, *end = '\0'; + switch (is_ctor_dtor (name)) { case SYM_CTOR: @@ -2552,7 +2550,8 @@ scan_prog_file (const char *prog_name, scanpass which_pass, if (! (filter & SCAN_INIT)) break; if (which_pass != PASS_LIB) - fatal_error ("init function found in object %s", prog_name); + fatal_error (input_location, "init function found in object %s", + prog_name); #ifndef LD_INIT_SWITCH add_to_list (&constructors, name); #endif @@ -2562,7 +2561,8 @@ scan_prog_file (const char *prog_name, scanpass which_pass, if (! (filter & SCAN_FINI)) break; if (which_pass != PASS_LIB) - fatal_error ("fini function found in object %s", prog_name); + fatal_error (input_location, "fini function found in object %s", + prog_name); #ifndef LD_FINI_SWITCH add_to_list (&destructors, name); #endif @@ -2618,7 +2618,7 @@ scan_libraries (const char *prog_name) /* If we do not have an `ldd', complain. */ if (ldd_file_name == 0) { - error ("cannot find 'ldd'"); + error ("cannot find %"); return; } @@ -2627,7 +2627,7 @@ scan_libraries (const char *prog_name) ldd_argv[argc++] = (char *) 0; /* Trace if needed. */ - if (vflag) + if (verbose) { const char **p_argv; const char *str; @@ -2643,7 +2643,7 @@ scan_libraries (const char *prog_name) pex = pex_init (PEX_USE_PIPES, "collect2", NULL); if (pex == NULL) - fatal_error ("pex_init failed: %m"); + fatal_error (input_location, "pex_init failed: %m"); errmsg = pex_run (pex, 0, ldd_file_name, real_ldd_argv, NULL, NULL, &err); if (errmsg != NULL) @@ -2651,10 +2651,10 @@ scan_libraries (const char *prog_name) if (err != 0) { errno = err; - fatal_error ("%s: %m", _(errmsg)); + fatal_error (input_location, "%s: %m", _(errmsg)); } else - fatal_error (errmsg); + fatal_error (input_location, errmsg); } int_handler = (void (*) (int)) signal (SIGINT, SIG_IGN); @@ -2664,7 +2664,7 @@ scan_libraries (const char *prog_name) inf = pex_read_output (pex, 0); if (inf == NULL) - fatal_error ("can't open ldd output: %m"); + fatal_error (input_location, "cannot open ldd output: %m"); if (debug) notice ("\nldd output with constructors/destructors.\n"); @@ -2682,7 +2682,7 @@ scan_libraries (const char *prog_name) name = p; if (strncmp (name, "not found", sizeof ("not found") - 1) == 0) - fatal_error ("dynamic dependency %s not found", buf); + fatal_error (input_location, "dynamic dependency %s not found", buf); /* Find the end of the symbol name. */ for (end = p; @@ -2694,7 +2694,8 @@ scan_libraries (const char *prog_name) if (access (name, R_OK) == 0) add_to_list (&libraries, name); else - fatal_error ("unable to open dynamic dependency '%s'", buf); + fatal_error (input_location, "unable to open dynamic dependency " + "%qs", buf); if (debug) fprintf (stderr, "\t%s\n", buf); @@ -2726,18 +2727,7 @@ scan_libraries (const char *prog_name) #ifdef OBJECT_FORMAT_COFF -#if defined (EXTENDED_COFF) - -# define GCC_SYMBOLS(X) (SYMHEADER(X).isymMax + SYMHEADER(X).iextMax) -# define GCC_SYMENT SYMR -# define GCC_OK_SYMBOL(X) ((X).st == stProc || (X).st == stGlobal) -# define GCC_SYMINC(X) (1) -# define GCC_SYMZERO(X) (SYMHEADER(X).isymMax) -# define GCC_CHECK_HDR(X) (PSYMTAB(X) != 0) - -#else - -# define GCC_SYMBOLS(X) (HEADER(ldptr).f_nsyms) +# define GCC_SYMBOLS(X) (HEADER (ldptr).f_nsyms) # define GCC_SYMENT SYMENT # if defined (C_WEAKEXT) # define GCC_OK_SYMBOL(X) \ @@ -2765,14 +2755,14 @@ scan_libraries (const char *prog_name) /* 0757 = U803XTOCMAGIC (AIX 4.3) and 0767 = U64_TOCMAGIC (AIX V5) */ #if TARGET_AIX_VERSION >= 51 # define GCC_CHECK_HDR(X) \ - ((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \ - || (HEADER (X).f_magic == 0767 && aix64_flag)) + (((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \ + || (HEADER (X).f_magic == 0767 && aix64_flag)) \ + && !(HEADER (X).f_flags & F_LOADONLY)) #else # define GCC_CHECK_HDR(X) \ - ((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \ - || (HEADER (X).f_magic == 0757 && aix64_flag)) -#endif - + (((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \ + || (HEADER (X).f_magic == 0757 && aix64_flag)) \ + && !(HEADER (X).f_flags & F_LOADONLY)) #endif #ifdef COLLECT_EXPORT_LIST @@ -2855,7 +2845,7 @@ scan_prog_file (const char *prog_name, scanpass which_pass, if ((ldptr = ldopen (CONST_CAST (char *, prog_name), ldptr)) != NULL) { if (! MY_ISCOFF (HEADER (ldptr).f_magic)) - fatal_error ("%s: not a COFF file", prog_name); + fatal_error (input_location, "%s: not a COFF file", prog_name); if (GCC_CHECK_HDR (ldptr)) { @@ -2891,6 +2881,30 @@ scan_prog_file (const char *prog_name, scanpass which_pass, switch (is_ctor_dtor (name)) { +#if TARGET_AIX_VERSION + /* Add AIX shared library initalisers/finalisers + to the constructors/destructors list of the + current module. */ + case SYM_AIXI: + if (! (filter & SCAN_CTOR)) + break; + if (is_shared && !aixlazy_flag +#ifdef COLLECT_EXPORT_LIST + && ! static_obj + && ! is_in_list (prog_name, static_libs.first) +#endif + ) + add_to_list (&constructors, name); + break; + + case SYM_AIXD: + if (! (filter & SCAN_DTOR)) + break; + if (is_shared && !aixlazy_flag) + add_to_list (&destructors, name); + break; +#endif + case SYM_CTOR: if (! (filter & SCAN_CTOR)) break; @@ -2953,22 +2967,25 @@ scan_prog_file (const char *prog_name, scanpass which_pass, provides an explicit export list. */ if (shared_obj && !is_shared && which_pass == PASS_OBJ && !export_flag) - add_to_list (&exports, name); + { + /* Do not auto-export __dso_handle or + __gcc_unwind_dbase. They are required + to be local to each module. */ + if (strcmp(name, "__dso_handle") != 0 + && strcmp(name, "__gcc_unwind_dbase") != 0) + { + add_to_list (&exports, name); + } + } #endif continue; } if (debug) -#if !defined(EXTENDED_COFF) fprintf (stderr, "\tsec=%d class=%d type=%s%o %s\n", symbol.n_scnum, symbol.n_sclass, (symbol.n_type ? "0" : ""), symbol.n_type, name); -#else - fprintf (stderr, - "\tiss = %5d, value = %5ld, index = %5d, name = %s\n", - symbol.iss, (long) symbol.value, symbol.index, name); -#endif } } } @@ -2985,7 +3002,8 @@ scan_prog_file (const char *prog_name, scanpass which_pass, } else { - fatal_error ("%s: cannot open as COFF file", prog_name); + fatal_error (input_location, "%s: cannot open as COFF file", + prog_name); } #ifdef COLLECT_EXPORT_LIST /* On AIX loop continues while there are more members in archive. */ @@ -2993,7 +3011,7 @@ scan_prog_file (const char *prog_name, scanpass which_pass, while (ldclose (ldptr) == FAILURE); #else /* Otherwise we simply close ldptr. */ - (void) ldclose(ldptr); + (void) ldclose (ldptr); #endif } #endif /* OBJECT_FORMAT_COFF */ @@ -3013,7 +3031,7 @@ resolve_lib_name (const char *name) if (libpaths[i]->max_len > l) l = libpaths[i]->max_len; - lib_buf = XNEWVEC (char, l + strlen(name) + 10); + lib_buf = XNEWVEC (char, l + strlen (name) + 10); for (i = 0; libpaths[i]; i++) { @@ -3024,7 +3042,7 @@ resolve_lib_name (const char *name) may contain directories both with trailing DIR_SEPARATOR and without it. */ const char *p = ""; - if (!IS_DIR_SEPARATOR (list->prefix[strlen(list->prefix)-1])) + if (!IS_DIR_SEPARATOR (list->prefix[strlen (list->prefix)-1])) p = "/"; for (j = 0; j < 2; j++) { @@ -3043,7 +3061,7 @@ resolve_lib_name (const char *name) if (debug) fprintf (stderr, "not found\n"); else - fatal_error ("library lib%s not found", name); + fatal_error (input_location, "library lib%s not found", name); return (NULL); } #endif /* COLLECT_EXPORT_LIST */ @@ -3095,7 +3113,8 @@ do_dsymutil (const char *output_file) { argv[1] = output_file; argv[2] = (char *) 0; - pex = collect_execute (dsymutil, real_argv, NULL, NULL, PEX_LAST | PEX_SEARCH); + pex = collect_execute (dsymutil, real_argv, NULL, NULL, + PEX_LAST | PEX_SEARCH, false); do_wait (dsymutil, pex); }