Here is another attempt to fix the bad interaction between --with-demangler-in-ld and -frepo processing.

This version of the patch always disables demangling in ld when repository files are present for the link. If demangling is requested (either by an explicit -Wl,--demangle option, by using COLLECT_NO_DEMANGLE, or just doing nothing and getting the default), it'll be performed by having collect2 filter the output streams no matter how you configured --with-demangler-in-ld. The exception is if -Wl,-Map is also provided, in which case it falls back on re-running the final link with the correct options to get a demangled map file after it is done with the repo file processing.

I could have implemented that last bit by having collect2 intercept the map file option and filter the file to demangle it, and make that the default behavior when collect2 is otherwise doing demangling itself. Given the previous argument that users can't possibly have any reason to want a demangled link map, I thought there might be objection to polluting collect2 by hacking it up to do just that. I mean, it's horrible enough that ld produces a demangled map file when you request demangled output.... :-P

Anyway, thoughts on this patch? It bootstrapped and regression tested OK on i686-linux, and I hand-tested it on every permutation of mangling/repository/map options I could think of.

-Sandra


2012-02-02  Sandra Loosemore <san...@codesourcery.com>
            Jason Merrill <ja...@redhat.com>
            Jakub Jelinek <ja...@redhat.com>

        PR c++/51910
        gcc/
        * collect2.c (dump_file): Add demangle_in_ld parameter so this
        can be tested dynamically instead only at compile-time.  Update
        callers.
        (main): Initialize no_demangle even when HAVE_LD_DEMANGLE.
        * collect2.h (dump_file): Adjust declaration.
        (no_demangle): Delare as extern.
        (DEMANGLE_IN_LD): Define.
        * tlink.c (do_tlink): Explicitly pass --no-demangle to linker
        for repo processing when HAVE_LD_DEMANGLE is defined, and demangle
        in collect2 instead of the linker.

        gcc/testsuite/
        * g++.dg/torture/pr51910.C: New testcase.


Index: gcc/collect2.c
===================================================================
--- gcc/collect2.c	(revision 183674)
+++ gcc/collect2.c	(working copy)
@@ -403,13 +403,13 @@ collect_exit (int status)
 
   if (ldout != 0 && ldout[0])
     {
-      dump_file (ldout, stdout);
+      dump_file (ldout, stdout, DEMANGLE_IN_LD);
       maybe_unlink (ldout);
     }
 
   if (lderrout != 0 && lderrout[0])
     {
-      dump_file (lderrout, stderr);
+      dump_file (lderrout, stderr, DEMANGLE_IN_LD);
       maybe_unlink (lderrout);
     }
 
@@ -515,7 +515,7 @@ extract_string (const char **pp)
 }
 
 void
-dump_file (const char *name, FILE *to)
+dump_file (const char *name, FILE *to, int demangle_in_ld)
 {
   FILE *stream = fopen (name, "r");
 
@@ -540,14 +540,10 @@ dump_file (const char *name, FILE *to)
 	  if (!strncmp (p, USER_LABEL_PREFIX, strlen (USER_LABEL_PREFIX)))
 	    p += strlen (USER_LABEL_PREFIX);
 
-#ifdef HAVE_LD_DEMANGLE
-	  result = 0;
-#else
-	  if (no_demangle)
+	  if (no_demangle || demangle_in_ld)
 	    result = 0;
 	  else
 	    result = cplus_demangle (p, DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE);
-#endif
 
 	  if (result)
 	    {
@@ -1114,9 +1110,8 @@ main (int argc, char **argv)
 
   num_c_args = argc + 9;
 
-#ifndef HAVE_LD_DEMANGLE
   no_demangle = !! getenv ("COLLECT_NO_DEMANGLE");
-
+#ifndef HAVE_LD_DEMANGLE
   /* Suppress demangling by the real linker, which may be broken.  */
   putenv (xstrdup ("COLLECT_NO_DEMANGLE=1"));
 #endif
@@ -1566,15 +1561,14 @@ main (int argc, char **argv)
 	    case '-':
 	      if (strcmp (arg, "--no-demangle") == 0)
 		{
-#ifndef HAVE_LD_DEMANGLE
 		  no_demangle = 1;
+#ifndef HAVE_LD_DEMANGLE
 		  ld1--;
 		  ld2--;
 #endif
 		}
 	      else if (strncmp (arg, "--demangle", 10) == 0)
 		{
-#ifndef HAVE_LD_DEMANGLE
 		  no_demangle = 0;
 		  if (arg[10] == '=')
 		    {
@@ -1585,6 +1579,7 @@ main (int argc, char **argv)
 		      else
 			current_demangling_style = style;
 		    }
+#ifndef HAVE_LD_DEMANGLE
 		  ld1--;
 		  ld2--;
 #endif
Index: gcc/collect2.h
===================================================================
--- gcc/collect2.h	(revision 183674)
+++ gcc/collect2.h	(working copy)
@@ -30,7 +30,7 @@ extern void collect_exit (int) ATTRIBUTE
 
 extern int collect_wait (const char *, struct pex_obj *);
 
-extern void dump_file (const char *, FILE *);
+extern void dump_file (const char *, FILE *, int);
 
 extern int file_exists (const char *);
 
@@ -40,6 +40,13 @@ extern const char *c_file_name;
 extern struct obstack temporary_obstack;
 extern char *temporary_firstobj;
 extern bool vflag, debug;
+extern int no_demangle;
+
+#ifdef HAVE_LD_DEMANGLE
+#define DEMANGLE_IN_LD 1
+#else
+#define DEMANGLE_IN_LD 0
+#endif
 
 extern void notice_translated (const char *, ...) ATTRIBUTE_PRINTF_1;
 extern void notice (const char *, ...) ATTRIBUTE_PRINTF_1;
Index: gcc/tlink.c
===================================================================
--- gcc/tlink.c	(revision 183674)
+++ gcc/tlink.c	(working copy)
@@ -766,8 +766,49 @@ scan_linker_output (const char *fname)
 void
 do_tlink (char **ld_argv, char **object_lst ATTRIBUTE_UNUSED)
 {
-  int exit = tlink_execute ("ld", ld_argv, ldout, lderrout);
+  int demangle_in_ld = DEMANGLE_IN_LD;
+  int map_file = FALSE;
+  int exit;
+  char **ld1_argv = ld_argv;
 
+#ifdef HAVE_LD_DEMANGLE
+  /* If there are repositories, proper processing of them depends on
+     the linker passing back mangled symbols.  So, explicitly tell the
+     linker not to demangle.  Also note whether the user requested a map
+     file, which requires special postprocessing.
+     We can skip this whole business if the user already asked
+     for non-demangled output.  */
+  if (!no_demangle)
+    {
+      int argc = 0;
+      int repo_files_exist = FALSE;
+      while (ld_argv[argc])
+	{
+	  if (*ld_argv[argc] == '-')
+	    {
+	      if (strncmp (ld_argv[argc], "-Map", 4) == 0)
+		map_file = TRUE;
+	    }
+	  else if (!repo_files_exist)
+	    {
+	      const char *p = frob_extension (ld_argv[argc], ".rpo");
+	      if (file_exists (p))
+		repo_files_exist = TRUE;
+	    }
+	  ++argc;
+	}
+      if (repo_files_exist)
+	{
+	  ld1_argv = XNEWVEC (char *, argc + 2);
+	  memcpy (ld1_argv, ld_argv, sizeof (ld_argv[0]) * argc);
+	  ld1_argv[argc] = CONST_CAST (char *, "--no-demangle");
+	  ld1_argv[argc + 1] = NULL;
+	  demangle_in_ld = FALSE;
+	}
+    }
+#endif
+
+  exit = tlink_execute ("ld", ld1_argv, ldout, lderrout);
   tlink_init ();
 
   if (exit)
@@ -781,8 +822,8 @@ do_tlink (char **ld_argv, char **object_
 	  {
 	    if (tlink_verbose >= 3)
 	      {
-		dump_file (ldout, stdout);
-		dump_file (lderrout, stderr);
+		dump_file (ldout, stdout, demangle_in_ld);
+		dump_file (lderrout, stderr, demangle_in_ld);
 	      }
 	    demangle_new_symbols ();
 	    if (! scan_linker_output (ldout)
@@ -792,13 +833,30 @@ do_tlink (char **ld_argv, char **object_
 	      break;
 	    if (tlink_verbose)
 	      fprintf (stderr, _("collect: relinking\n"));
-	    exit = tlink_execute ("ld", ld_argv, ldout, lderrout);
+	    exit = tlink_execute ("ld", ld1_argv, ldout, lderrout);
 	  }
     }
 
-  dump_file (ldout, stdout);
+#ifdef HAVE_LD_DEMANGLE
+  if (!demangle_in_ld)
+    {
+      XDELETEVEC (ld1_argv);
+      /* If the user specified all of demangling, a map file, and repositories,
+	 we must re-link once more with the original options to get the map
+	 file demangled. */
+      if (map_file)
+	{
+	  demangle_in_ld = TRUE;
+	  if (tlink_verbose)
+	    fprintf (stderr, _("collect: relinking\n"));
+	  exit = tlink_execute ("ld", ld_argv, ldout, lderrout);
+	}
+    }
+#endif
+
+  dump_file (ldout, stdout, demangle_in_ld);
   unlink (ldout);
-  dump_file (lderrout, stderr);
+  dump_file (lderrout, stderr, demangle_in_ld);
   unlink (lderrout);
   if (exit)
     {
Index: gcc/testsuite/g++.dg/torture/pr51910.C
===================================================================
--- gcc/testsuite/g++.dg/torture/pr51910.C	(revision 0)
+++ gcc/testsuite/g++.dg/torture/pr51910.C	(revision 0)
@@ -0,0 +1,19 @@
+// PR c++/51910 
+// Check that -frepo works in the presence of linker symbol demangling.
+//
+// { dg-options "-frepo -Wl,--demangle" }
+// { dg-require-host-local "" }
+// { dg-skip-if "dkms are not final links" { vxworks_kernel } }
+
+template<typename T>
+struct Foo
+{
+  virtual ~Foo() { }
+};
+
+int main( int, char*[] )
+{
+  Foo<int> test;
+}
+
+// { dg-final { cleanup-repo-files } }

Reply via email to