This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH,lto] Fix PR42690 and related LTO-vs-static-linking issues.


    Hi list,

  In PR42690(*), GCC is configured with --disable-shared.  This effectively
means that all compilations performed by the built compiler have -static in
effect, but implicitly: there is no actual -static among the command-line
options and thus any related specs do not become activated.  This leads to
unresolved symbols in the final link, owing to the late optimisations
performed by LTO/ltrans introducing new undefined symbols that weren't visible
earlier in either the normal generated object file or the LTO symtab it carries.

  Similar problems arise on PE-COFF even without configuring with
--disable-shared, as I discussed earlier on the main list(**), since even
dynamic symbols are effectively resolved statically through the use of import
library stubs.

  This patch resolves all these problems using the method suggested by Rafael
in comment 12 of the PR audit trail: it uses linker plugin -pass-through=
options to pass libgcc and libc back to the linker one more time after all the
ltrans-generated objects have been added into the link.  It uses a new spec
function to process the link_gcc_c__sequence spec, which should guarantee that
it takes account of platform-specific variations in libc naming and will
incorporate all the effects of any specs based on -static or -static-libgcc on
the way.

gcc/ChangeLog:

2010-11-16  Dave Korn  <...

	PR driver/42690
	* gcc.c (LINK_COMMAND_SPEC): Remove hard-coded pass-through plugin
	options, replace by call of pass-through-libs spec function to process
	link_gcc_c_sequence spec.
	(lto_libgcc_spec): Delete variable.
	(static_specs[]): Remove related entry.
	(static_spec_functions[]): Add new entry for pass-through-libs.
	(main): Don't generate deleted lto_libgcc_spec.
	(pass_through_libs_spec_func): New function to implement the new
	pass-through-libs spec function.
	* doc/invoke.texi (pass-through-libs): Document new spec function.

  Bootstrapped and tested on i686-pc-cygwin without new regressions(***).  Now
running an LTO bootstrap on that platform, but last time I tested it tripped
the unrelated PR45325 in libcpp and I expect it still does.

  Also tested on x86_64-unknown-linux-gnu vs. all eight combinations of a)
LTO-enabled vs. non-LTO-enabled bootstrap, b) GOLD vs. GNU LD for linker and
plugin, c) --enable-static vs. --disable-static, without any regressions, and
fixing bootstrap in three cases (two vs. LD, one vs. GOLD, as even GOLD
currently fails to lto-bootstrap with --disable-static).

  OK for trunk?

    cheers,
      DaveK
-- 
(*)   - http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42690
(**)  - http://gcc.gnu.org/ml/gcc/2010-10/msg00204.html
(***) - http://gcc.gnu.org/ml/gcc-testresults/2010-11/msg01011.html
Index: gcc/gcc.c
===================================================================
--- gcc/gcc.c	(revision 166803)
+++ gcc/gcc.c	(working copy)
@@ -284,6 +284,7 @@ static const char *print_asm_header_spec_function
 static const char *compare_debug_dump_opt_spec_function (int, const char **);
 static const char *compare_debug_self_opt_spec_function (int, const char **);
 static const char *compare_debug_auxbase_opt_spec_function (int, const char **);
+static const char *pass_through_libs_spec_func (int, const char **);
 
 /* The Specs Language
 
@@ -656,8 +657,7 @@ proper position among the other output files.  */
     -plugin %(linker_plugin_file) \
     -plugin-opt=%(lto_wrapper) \
     -plugin-opt=-fresolution=%u.res \
-    %{static|static-libgcc:-plugin-opt=-pass-through=%(lto_libgcc)}	\
-    %{static:-plugin-opt=-pass-through=-lc}	\
+    %{!nostdlib:%{!nodefaultlibs:%:pass-through-libs(%(link_gcc_c_sequence))}} \
     } \
     %{flto*:%<fcompare-debug*} \
     %{flto*} %l " LINK_PIE_SPEC \
@@ -712,7 +712,6 @@ static const char *linker_name_spec = LINKER_NAME;
 static const char *linker_plugin_file_spec = "";
 static const char *lto_wrapper_spec = "";
 static const char *lto_gcc_spec = "";
-static const char *lto_libgcc_spec = "";
 static const char *link_command_spec = LINK_COMMAND_SPEC;
 static const char *link_libgcc_spec = LINK_LIBGCC_SPEC;
 static const char *startfile_prefix_spec = STARTFILE_PREFIX_SPEC;
@@ -1197,7 +1196,6 @@ static struct spec_list static_specs[] =
   INIT_STATIC_SPEC ("linker_plugin_file",	&linker_plugin_file_spec),
   INIT_STATIC_SPEC ("lto_wrapper",		&lto_wrapper_spec),
   INIT_STATIC_SPEC ("lto_gcc",			&lto_gcc_spec),
-  INIT_STATIC_SPEC ("lto_libgcc",		&lto_libgcc_spec),
   INIT_STATIC_SPEC ("link_libgcc",		&link_libgcc_spec),
   INIT_STATIC_SPEC ("md_exec_prefix",		&md_exec_prefix),
   INIT_STATIC_SPEC ("md_startfile_prefix",	&md_startfile_prefix),
@@ -1242,6 +1240,7 @@ static const struct spec_function static_spec_func
   { "compare-debug-dump-opt",	compare_debug_dump_opt_spec_function },
   { "compare-debug-self-opt",	compare_debug_self_opt_spec_function },
   { "compare-debug-auxbase-opt", compare_debug_auxbase_opt_spec_function },
+  { "pass-through-libs",	pass_through_libs_spec_func },
 #ifdef EXTRA_SPEC_FUNCTIONS
   EXTRA_SPEC_FUNCTIONS
 #endif
@@ -6803,11 +6802,6 @@ warranty; not even for MERCHANTABILITY or FITNESS
 						 false);
 	  if (!linker_plugin_file_spec)
 	    fatal_error ("-fuse-linker-plugin, but " LTOPLUGINSONAME " not found");
-
-	  lto_libgcc_spec = find_a_file (&startfile_prefixes, "libgcc.a",
-					 R_OK, true);
-	  if (!lto_libgcc_spec)
-	    fatal_error ("could not find libgcc.a");
 	}
       lto_gcc_spec = argv[0];
 
@@ -8188,3 +8182,33 @@ compare_debug_auxbase_opt_spec_function (int arg,
 
   return name;
 }
+
+/* %:pass-through-libs spec function.  Finds all -l options and input
+   file names in the lib spec passed to it, and makes a list of them
+   prepended with the plugin option to cause them to be passed through
+   to the final link after all the new object files have been added.  */
+
+const char *
+pass_through_libs_spec_func (int argc, const char **argv)
+{
+  char *prepended = xstrdup (" ");
+  int n;
+  /* Shlemiel the painter's algorithm.  Innately horrible, but at least
+     we know that there will never be more than a handful of strings to
+     concat, and it's only once per run, so it's not worth optimising.  */
+  for (n = 0; n < argc; n++)
+    {
+      char *old = prepended;
+      /* Anything that isn't an option is a full path to an output
+         file; pass it through if it ends in '.a'.  Among options,
+	 pass only -l.  */
+      if (argv[n][0] == '-'
+		? argv[n][1] == 'l'
+		: !strcmp (".a", argv[n] + strlen (argv[n]) - 2))
+	prepended = concat (prepended, "-plugin-opt=-pass-through=",
+		argv[n], " ", NULL);
+      if (prepended != old)
+	free (old);
+    }
+  return prepended;
+}
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 166803)
+++ gcc/doc/invoke.texi	(working copy)
@@ -9694,6 +9694,18 @@ its usage:
 %:remove-outfile(-lm)
 @end smallexample
 
+@item @code{pass-through-libs}
+The @code{pass-through-libs} spec function takes any number of arguments.  It
+finds any @option{-l} options and any non-options ending in ".a" (which it
+assumes are the names of linker input library archive files) and returns a
+result containing all the found arguments each prepended by
+@option{-plugin-opt=-pass-through=} and joined by spaces.  This list is
+intended to be passed to the LTO linker plugin.
+
+@smallexample
+%:pass-through-libs(%G %L %G)
+@end smallexample
+
 @item @code{print-asm-header}
 The @code{print-asm-header} function takes no arguments and simply
 prints a banner like:

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]