diff gcc/collect2.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
line wrap: on
line diff
--- a/gcc/collect2.c	Thu Oct 25 07:37:49 2018 +0900
+++ b/gcc/collect2.c	Thu Feb 13 11:34:05 2020 +0900
@@ -1,6 +1,6 @@
 /* Collect static initialization info into data structures that can be
    traversed by C++ initialization and finalization routines.
-   Copyright (C) 1992-2018 Free Software Foundation, Inc.
+   Copyright (C) 1992-2020 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).
@@ -30,6 +30,8 @@
 #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
@@ -203,8 +205,8 @@
 static int shared_obj;			/* true if -shared */
 static int static_obj;			/* true if -static */
 
-static const char *c_file;		/* <xxx>.c for constructor/destructor list.  */
-static const char *o_file;		/* <xxx>.o for constructor/destructor list.  */
+static char *c_file;		/* <xxx>.c for constructor/destructor list.  */
+static char *o_file;		/* <xxx>.o for constructor/destructor list.  */
 #ifdef COLLECT_EXPORT_LIST
 static const char *export_file;		/* <xxx>.x for AIX export list.  */
 #endif
@@ -614,7 +616,7 @@
 
    Return 0 if not found, otherwise return its name, allocated with malloc.  */
 
-#if defined (OBJECT_FORMAT_NONE) || defined (OBJECT_FORMAT_COFF)
+#ifdef OBJECT_FORMAT_NONE
 
 /* Add an entry for the object file NAME to object file list LIST.
    New entries are added at the end of the list. The original pointer
@@ -634,7 +636,7 @@
 
   list->last = n;
 }
-#endif
+#endif /* OBJECT_FORMAT_NONE */
 
 
 /* Perform a link-time recompilation and relink if any of the object
@@ -699,7 +701,8 @@
       size_t num_files;
 
       if (!lto_wrapper)
-	fatal_error (input_location, "COLLECT_LTO_WRAPPER must be set");
+	fatal_error (input_location, "environment variable "
+		     "%<COLLECT_LTO_WRAPPER%> must be set");
 
       num_lto_c_args++;
 
@@ -804,7 +807,9 @@
       /* 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, HAVE_GNU_LD && at_file_supplied);
-      post_ld_pass (true);
+      /* 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);
@@ -814,10 +819,35 @@
       /* 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, HAVE_GNU_LD && at_file_supplied);
-      post_ld_pass (false);
+      /* No LTO objects were found, so no new temp file.  */
+      post_ld_pass (/*temp_file*/false);
     }
   else
-    post_ld_pass (true);
+    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;
+    }
 }
 
 /* Main program.  */
@@ -831,6 +861,7 @@
       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] =
@@ -838,7 +869,8 @@
       "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";
@@ -979,13 +1011,21 @@
   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;
 
@@ -993,8 +1033,6 @@
       {
 	if (! strcmp (argv[i], "-debug"))
 	  debug = true;
-        else if (! strcmp (argv[i], "-flto-partition=none"))
-	  no_partition = true;
 	else if (!strncmp (argv[i], "-fno-lto", 8))
 	  lto_mode = LTO_MODE_NONE;
         else if (! strcmp (argv[i], "-plugin"))
@@ -1007,6 +1045,17 @@
 	  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
 	/* These flags are position independent, although their order
@@ -1027,7 +1076,35 @@
 	    aixlazy_flag = 1;
 #endif
       }
-    verbose = debug;
+
+    obstack_begin (&temporary_obstack, 0);
+    temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0);
+
+#ifndef HAVE_LD_DEMANGLE
+  current_demangling_style = auto_demangling;
+#endif
+
+    /* 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);
+
+    verbose = verbose || debug;
+    save_temps = save_temps || debug;
     find_file_set_debug (debug);
     if (use_plugin)
       lto_mode = LTO_MODE_NONE;
@@ -1035,27 +1112,6 @@
       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);
-
-#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++;
-    }
-  obstack_free (&temporary_obstack, temporary_firstobj);
-
   /* -fno-profile-arcs -fno-test-coverage -fno-branch-probabilities
      -fno-exceptions -w -fno-whole-program */
   num_c_args += 6;
@@ -1096,7 +1152,8 @@
   /* Maybe we know the right file to use (if not cross).  */
   ld_file_name = 0;
 #ifdef DEFAULT_LINKER
-  if (selected_linker == USE_BFD_LD || selected_linker == USE_GOLD_LD)
+  if (selected_linker == USE_BFD_LD || selected_linker == USE_GOLD_LD ||
+      selected_linker == USE_LLD_LD)
     {
       char *linker_name;
 # ifdef HOST_EXECUTABLE_SUFFIX
@@ -1203,8 +1260,22 @@
   *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
@@ -1213,6 +1284,7 @@
       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";
@@ -1315,7 +1387,7 @@
 	      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--;
 		}
@@ -1349,7 +1421,7 @@
 
 		  stream = fopen (list_filename, "r");
 		  if (stream == NULL)
-		    fatal_error (input_location, "can't open %s: %m",
+		    fatal_error (input_location, "cannot open %s: %m",
 				 list_filename);
 
 		  while (fgets (buf, sizeof buf, stream) != NULL)
@@ -1469,7 +1541,7 @@
 		      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;
 		    }
@@ -1593,7 +1665,7 @@
       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");
     }
@@ -1656,7 +1728,7 @@
        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)
       {
@@ -1668,10 +1740,8 @@
 	if (lto_mode != LTO_MODE_NONE)
 	  maybe_run_lto_and_relink (ld1_argv, object_lst, object, false);
 	else
-	  post_ld_pass (false);
-
-	maybe_unlink (c_file);
-	maybe_unlink (o_file);
+	  post_ld_pass (/*temp_file*/false);
+
 	return 0;
       }
   }
@@ -1716,10 +1786,10 @@
 #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);
@@ -1740,7 +1810,7 @@
 #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);
@@ -1822,19 +1892,19 @@
 
   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, HAVE_GNU_LD && at_file_supplied);
-      post_ld_pass (false);
+      post_ld_pass (/*temp_file*/false);
     }
 
   /* Let scan_prog_file do any final mods (OSF/rose needs this for
@@ -1859,9 +1929,10 @@
 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;
     }
 
@@ -2291,38 +2362,52 @@
 
 /* Check to make sure the file is an LTO object file.  */
 
-static bool
-maybe_lto_object_file (const char *prog_name)
+static int
+has_lto_section (void *data, const char *name ATTRIBUTE_UNUSED,
+		 off_t offset ATTRIBUTE_UNUSED,
+		 off_t length ATTRIBUTE_UNUSED)
 {
-  FILE *f;
-  unsigned char buf[4];
-  int i;
-
-  static unsigned char elfmagic[4] = { 0x7f, 'E', 'L', 'F' };
-  static unsigned char coffmagic[2] = { 0x4c, 0x01 };
-  static unsigned char 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 }
-  };
-
-  f = fopen (prog_name, "rb");
-  if (f == NULL)
+  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
+is_lto_object_file (const char *prog_name)
+{
+  const char *errmsg;
+  int err;
+  int found = 0;
+  off_t inoff = 0;
+  int infd = open (prog_name, O_RDONLY | O_BINARY);
+
+  if (infd == -1)
     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)
+
+  simple_object_read *inobj = simple_object_start_read (infd, inoff,
+							LTO_SEGMENT_NAME,
+							&errmsg, &err);
+  if (!inobj)
+    return false;
+
+  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;
 }
 
@@ -2345,7 +2430,6 @@
   int err;
   char *p, buf[1024];
   FILE *inf;
-  int found_lto = 0;
 
   if (which_pass == PASS_SECOND)
     return;
@@ -2353,12 +2437,17 @@
   /* 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 (&lto_objects, prog_name);
+      }
+      return;
+    }
 
   /* If we do not have an `nm', complain.  */
   if (nm_file_name == 0)
-    fatal_error (input_location, "cannot find 'nm'");
+    fatal_error (input_location, "cannot find %<nm%>");
 
   nm_argv[argc++] = nm_file_name;
   if (NM_FLAGS[0] != '\0')
@@ -2384,7 +2473,7 @@
 
   pex = pex_init (PEX_USE_PIPES, "collect2", NULL);
   if (pex == NULL)
-    fatal_error (input_location, "pex_init failed: %m");
+    fatal_error (input_location, "%<pex_init%> failed: %m");
 
   errmsg = pex_run (pex, 0, nm_file_name, real_nm_argv, NULL, HOST_BIT_BUCKET,
 		    &err);
@@ -2406,15 +2495,10 @@
 
   inf = pex_read_output (pex, 0);
   if (inf == NULL)
-    fatal_error (input_location, "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)
@@ -2425,30 +2509,6 @@
       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 (&lto_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.  */
@@ -2558,7 +2618,7 @@
   /* If we do not have an `ldd', complain.  */
   if (ldd_file_name == 0)
     {
-      error ("cannot find 'ldd'");
+      error ("cannot find %<ldd%>");
       return;
     }
 
@@ -2604,7 +2664,7 @@
 
   inf = pex_read_output (pex, 0);
   if (inf == NULL)
-    fatal_error (input_location, "can't open ldd output: %m");
+    fatal_error (input_location, "cannot open ldd output: %m");
 
   if (debug)
     notice ("\nldd output with constructors/destructors.\n");
@@ -2634,8 +2694,8 @@
       if (access (name, R_OK) == 0)
 	add_to_list (&libraries, name);
       else
-	fatal_error (input_location, "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);
@@ -2763,10 +2823,8 @@
   LDFILE *ldptr = NULL;
   int sym_index, sym_count;
   int is_shared = 0;
-  int found_lto = 0;
-
-  if (which_pass != PASS_FIRST && which_pass != PASS_OBJ
-      && which_pass != PASS_LTOINFO)
+
+  if (which_pass != PASS_FIRST && which_pass != PASS_OBJ)
     return;
 
 #ifdef COLLECT_EXPORT_LIST
@@ -2779,7 +2837,6 @@
      eliminate scan_libraries() function.  */
   do
     {
-      found_lto = 0;
 #endif
       /* Some platforms (e.g. OSF4) declare ldopen as taking a
 	 non-const char * filename parameter, even though it will not
@@ -2822,19 +2879,6 @@
 			++name;
 #endif
 
-                      if (which_pass == PASS_LTOINFO)
-                        {
-			  if (found_lto)
-			    continue;
-			  if (strncmp (name, "__gnu_lto_v1", 12) == 0)
-			    {
-			      add_lto_object (&lto_objects, prog_name);
-			      found_lto = 1;
-			      break;
-			    }
-			  continue;
-			}
-
 		      switch (is_ctor_dtor (name))
 			{
 #if TARGET_AIX_VERSION