1 /* Scan linker error messages for missing template instantiations and provide
2    them.
3 
4    Copyright (C) 1995, 1998, 1999, 2000, 2001, 2003, 2004, 2005
5    Free Software Foundation, Inc.
6    Contributed by Jason Merrill (jason@cygnus.com).
7 
8 This file is part of GCC.
9 
10 GCC is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 2, or (at your option) any later
13 version.
14 
15 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18 for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with GCC; see the file COPYING.  If not, write to the Free
22 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
23 02110-1301, USA.  */
24 
25 #include "config.h"
26 #include "system.h"
27 #include "coretypes.h"
28 #include "tm.h"
29 #include "intl.h"
30 #include "obstack.h"
31 #include "hashtab.h"
32 #include "demangle.h"
33 #include "collect2.h"
34 
35 #define MAX_ITERATIONS 17
36 
37 /* Defined in the automatically-generated underscore.c.  */
38 extern int prepends_underscore;
39 
40 static int tlink_verbose;
41 
42 static char initial_cwd[MAXPATHLEN + 1];
43 
44 /* Hash table boilerplate for working with htab_t.  We have hash tables
45    for symbol names, file names, and demangled symbols.  */
46 
47 typedef struct symbol_hash_entry
48 {
49   const char *key;
50   struct file_hash_entry *file;
51   int chosen;
52   int tweaking;
53   int tweaked;
54 } symbol;
55 
56 typedef struct file_hash_entry
57 {
58   const char *key;
59   const char *args;
60   const char *dir;
61   const char *main;
62   int tweaking;
63 } file;
64 
65 typedef struct demangled_hash_entry
66 {
67   const char *key;
68   const char *mangled;
69 } demangled;
70 
71 /* Hash and comparison functions for these hash tables.  */
72 
73 static int hash_string_eq (const void *, const void *);
74 static hashval_t hash_string_hash (const void *);
75 
76 static int
hash_string_eq(const void * s1_p,const void * s2_p)77 hash_string_eq (const void *s1_p, const void *s2_p)
78 {
79   const char *const *s1 = (const char *const *) s1_p;
80   const char *s2 = (const char *) s2_p;
81   return strcmp (*s1, s2) == 0;
82 }
83 
84 static hashval_t
hash_string_hash(const void * s_p)85 hash_string_hash (const void *s_p)
86 {
87   const char *const *s = (const char *const *) s_p;
88   return (*htab_hash_string) (*s);
89 }
90 
91 static htab_t symbol_table;
92 
93 static struct symbol_hash_entry * symbol_hash_lookup (const char *, int);
94 static struct file_hash_entry * file_hash_lookup (const char *);
95 static struct demangled_hash_entry *demangled_hash_lookup (const char *, int);
96 static void symbol_push (symbol *);
97 static symbol * symbol_pop (void);
98 static void file_push (file *);
99 static file * file_pop (void);
100 static void tlink_init (void);
101 static int tlink_execute (const char *, char **, const char *, const char *);
102 static char * frob_extension (const char *, const char *);
103 static char * obstack_fgets (FILE *, struct obstack *);
104 static char * tfgets (FILE *);
105 static char * pfgets (FILE *);
106 static void freadsym (FILE *, file *, int);
107 static void read_repo_file (file *);
108 static void maybe_tweak (char *, file *);
109 static int recompile_files (void);
110 static int read_repo_files (char **);
111 static void demangle_new_symbols (void);
112 static int scan_linker_output (const char *);
113 
114 /* Look up an entry in the symbol hash table.  */
115 
116 static struct symbol_hash_entry *
symbol_hash_lookup(const char * string,int create)117 symbol_hash_lookup (const char *string, int create)
118 {
119   void **e;
120   e = htab_find_slot_with_hash (symbol_table, string,
121 				(*htab_hash_string) (string),
122 				create ? INSERT : NO_INSERT);
123   if (e == NULL)
124     return NULL;
125   if (*e == NULL)
126     {
127       struct symbol_hash_entry *v;
128       *e = v = XCNEW (struct symbol_hash_entry);
129       v->key = xstrdup (string);
130     }
131   return *e;
132 }
133 
134 static htab_t file_table;
135 
136 /* Look up an entry in the file hash table.  */
137 
138 static struct file_hash_entry *
file_hash_lookup(const char * string)139 file_hash_lookup (const char *string)
140 {
141   void **e;
142   e = htab_find_slot_with_hash (file_table, string,
143 				(*htab_hash_string) (string),
144 				INSERT);
145   if (*e == NULL)
146     {
147       struct file_hash_entry *v;
148       *e = v = XCNEW (struct file_hash_entry);
149       v->key = xstrdup (string);
150     }
151   return *e;
152 }
153 
154 static htab_t demangled_table;
155 
156 /* Look up an entry in the demangled name hash table.  */
157 
158 static struct demangled_hash_entry *
demangled_hash_lookup(const char * string,int create)159 demangled_hash_lookup (const char *string, int create)
160 {
161   void **e;
162   e = htab_find_slot_with_hash (demangled_table, string,
163 				(*htab_hash_string) (string),
164 				create ? INSERT : NO_INSERT);
165   if (e == NULL)
166     return NULL;
167   if (*e == NULL)
168     {
169       struct demangled_hash_entry *v;
170       *e = v = XCNEW (struct demangled_hash_entry);
171       v->key = xstrdup (string);
172     }
173   return *e;
174 }
175 
176 /* Stack code.  */
177 
178 struct symbol_stack_entry
179 {
180   symbol *value;
181   struct symbol_stack_entry *next;
182 };
183 struct obstack symbol_stack_obstack;
184 struct symbol_stack_entry *symbol_stack;
185 
186 struct file_stack_entry
187 {
188   file *value;
189   struct file_stack_entry *next;
190 };
191 struct obstack file_stack_obstack;
192 struct file_stack_entry *file_stack;
193 
194 static void
symbol_push(symbol * p)195 symbol_push (symbol *p)
196 {
197   struct symbol_stack_entry *ep = obstack_alloc
198     (&symbol_stack_obstack, sizeof (struct symbol_stack_entry));
199   ep->value = p;
200   ep->next = symbol_stack;
201   symbol_stack = ep;
202 }
203 
204 static symbol *
symbol_pop(void)205 symbol_pop (void)
206 {
207   struct symbol_stack_entry *ep = symbol_stack;
208   symbol *p;
209   if (ep == NULL)
210     return NULL;
211   p = ep->value;
212   symbol_stack = ep->next;
213   obstack_free (&symbol_stack_obstack, ep);
214   return p;
215 }
216 
217 static void
file_push(file * p)218 file_push (file *p)
219 {
220   struct file_stack_entry *ep;
221 
222   if (p->tweaking)
223     return;
224 
225   ep = obstack_alloc
226     (&file_stack_obstack, sizeof (struct file_stack_entry));
227   ep->value = p;
228   ep->next = file_stack;
229   file_stack = ep;
230   p->tweaking = 1;
231 }
232 
233 static file *
file_pop(void)234 file_pop (void)
235 {
236   struct file_stack_entry *ep = file_stack;
237   file *p;
238   if (ep == NULL)
239     return NULL;
240   p = ep->value;
241   file_stack = ep->next;
242   obstack_free (&file_stack_obstack, ep);
243   p->tweaking = 0;
244   return p;
245 }
246 
247 /* Other machinery.  */
248 
249 /* Initialize the tlink machinery.  Called from do_tlink.  */
250 
251 static void
tlink_init(void)252 tlink_init (void)
253 {
254   const char *p;
255 
256   symbol_table = htab_create (500, hash_string_hash, hash_string_eq,
257 			      NULL);
258   file_table = htab_create (500, hash_string_hash, hash_string_eq,
259 			    NULL);
260   demangled_table = htab_create (500, hash_string_hash, hash_string_eq,
261 				 NULL);
262 
263   obstack_begin (&symbol_stack_obstack, 0);
264   obstack_begin (&file_stack_obstack, 0);
265 
266   p = getenv ("TLINK_VERBOSE");
267   if (p)
268     tlink_verbose = atoi (p);
269   else
270     {
271       tlink_verbose = 1;
272       if (vflag)
273 	tlink_verbose = 2;
274       if (debug)
275 	tlink_verbose = 3;
276     }
277 
278   getcwd (initial_cwd, sizeof (initial_cwd));
279 }
280 
281 static int
tlink_execute(const char * prog,char ** argv,const char * outname,const char * errname)282 tlink_execute (const char *prog, char **argv, const char *outname,
283 	       const char *errname)
284 {
285   struct pex_obj *pex;
286 
287   pex = collect_execute (prog, argv, outname, errname);
288   return collect_wait (prog, pex);
289 }
290 
291 static char *
frob_extension(const char * s,const char * ext)292 frob_extension (const char *s, const char *ext)
293 {
294   const char *p = strrchr (s, '/');
295   if (! p)
296     p = s;
297   p = strrchr (p, '.');
298   if (! p)
299     p = s + strlen (s);
300 
301   obstack_grow (&temporary_obstack, s, p - s);
302   return obstack_copy0 (&temporary_obstack, ext, strlen (ext));
303 }
304 
305 static char *
obstack_fgets(FILE * stream,struct obstack * ob)306 obstack_fgets (FILE *stream, struct obstack *ob)
307 {
308   int c;
309   while ((c = getc (stream)) != EOF && c != '\n')
310     obstack_1grow (ob, c);
311   if (obstack_object_size (ob) == 0)
312     return NULL;
313   obstack_1grow (ob, '\0');
314   return XOBFINISH (ob, char *);
315 }
316 
317 static char *
tfgets(FILE * stream)318 tfgets (FILE *stream)
319 {
320   return obstack_fgets (stream, &temporary_obstack);
321 }
322 
323 static char *
pfgets(FILE * stream)324 pfgets (FILE *stream)
325 {
326   return xstrdup (tfgets (stream));
327 }
328 
329 /* Real tlink code.  */
330 
331 /* Subroutine of read_repo_file.  We are reading the repo file for file F,
332    which is coming in on STREAM, and the symbol that comes next in STREAM
333    is offered, chosen or provided if CHOSEN is 0, 1 or 2, respectively.
334 
335    XXX "provided" is unimplemented, both here and in the compiler.  */
336 
337 static void
freadsym(FILE * stream,file * f,int chosen)338 freadsym (FILE *stream, file *f, int chosen)
339 {
340   symbol *sym;
341 
342   {
343     const char *name = tfgets (stream);
344     sym = symbol_hash_lookup (name, true);
345   }
346 
347   if (sym->file == NULL)
348     {
349       /* We didn't have this symbol already, so we choose this file.  */
350 
351       symbol_push (sym);
352       sym->file = f;
353       sym->chosen = chosen;
354     }
355   else if (chosen)
356     {
357       /* We want this file; cast aside any pretender.  */
358 
359       if (sym->chosen && sym->file != f)
360 	{
361 	  if (sym->chosen == 1)
362 	    file_push (sym->file);
363 	  else
364 	    {
365 	      file_push (f);
366 	      f = sym->file;
367 	      chosen = sym->chosen;
368 	    }
369 	}
370       sym->file = f;
371       sym->chosen = chosen;
372     }
373 }
374 
375 /* Read in the repo file denoted by F, and record all its information.  */
376 
377 static void
read_repo_file(file * f)378 read_repo_file (file *f)
379 {
380   char c;
381   FILE *stream = fopen (f->key, "r");
382 
383   if (tlink_verbose >= 2)
384     fprintf (stderr, "%s", _("collect: reading %s\n"), f->key);
385 
386   while (fscanf (stream, "%c ", &c) == 1)
387     {
388       switch (c)
389 	{
390 	case 'A':
391 	  f->args = pfgets (stream);
392 	  break;
393 	case 'D':
394 	  f->dir = pfgets (stream);
395 	  break;
396 	case 'M':
397 	  f->main = pfgets (stream);
398 	  break;
399 	case 'P':
400 	  freadsym (stream, f, 2);
401 	  break;
402 	case 'C':
403 	  freadsym (stream, f, 1);
404 	  break;
405 	case 'O':
406 	  freadsym (stream, f, 0);
407 	  break;
408 	}
409       obstack_free (&temporary_obstack, temporary_firstobj);
410     }
411   fclose (stream);
412   if (f->args == NULL)
413     f->args = getenv ("COLLECT_GCC_OPTIONS");
414   if (f->dir == NULL)
415     f->dir = ".";
416 }
417 
418 /* We might want to modify LINE, which is a symbol line from file F.  We do
419    this if either we saw an error message referring to the symbol in
420    question, or we have already allocated the symbol to another file and
421    this one wants to emit it as well.  */
422 
423 static void
maybe_tweak(char * line,file * f)424 maybe_tweak (char *line, file *f)
425 {
426   symbol *sym = symbol_hash_lookup (line + 2, false);
427 
428   if ((sym->file == f && sym->tweaking)
429       || (sym->file != f && line[0] == 'C'))
430     {
431       sym->tweaking = 0;
432       sym->tweaked = 1;
433 
434       if (line[0] == 'O')
435 	line[0] = 'C';
436       else
437 	line[0] = 'O';
438     }
439 }
440 
441 /* Update the repo files for each of the object files we have adjusted and
442    recompile.  */
443 
444 static int
recompile_files(void)445 recompile_files (void)
446 {
447   file *f;
448 
449   putenv (xstrdup ("COMPILER_PATH="));
450   putenv (xstrdup ("LIBRARY_PATH="));
451 
452   while ((f = file_pop ()) != NULL)
453     {
454       char *line;
455       const char *p, *q;
456       char **argv;
457       struct obstack arg_stack;
458       FILE *stream = fopen (f->key, "r");
459       const char *const outname = frob_extension (f->key, ".rnw");
460       FILE *output = fopen (outname, "w");
461 
462       while ((line = tfgets (stream)) != NULL)
463 	{
464 	  switch (line[0])
465 	    {
466 	    case 'C':
467 	    case 'O':
468 	      maybe_tweak (line, f);
469 	    }
470 	  fprintf (output, "%s\n", line);
471 	}
472       fclose (stream);
473       fclose (output);
474       /* On Windows "rename" returns -1 and sets ERRNO to EACCESS if
475 	 the new file name already exists.  Therefore, we explicitly
476 	 remove the old file first.  */
477       if (remove (f->key) == -1)
478 	fatal_perror ("removing .rpo file");
479       if (rename (outname, f->key) == -1)
480 	fatal_perror ("renaming .rpo file");
481 
482       if (!f->args)
483 	{
484 	  error ("repository file '%s' does not contain command-line "
485 		 "arguments", f->key);
486 	  return 0;
487 	}
488 
489       /* Build a null-terminated argv array suitable for
490 	 tlink_execute().  Manipulate arguments on the arg_stack while
491 	 building argv on the temporary_obstack.  */
492 
493       obstack_init (&arg_stack);
494       obstack_ptr_grow (&temporary_obstack, c_file_name);
495 
496       for (p = f->args; *p != '\0'; p = q + 1)
497 	{
498 	  /* Arguments are delimited by single-quotes.  Find the
499 	     opening quote.  */
500 	  p = strchr (p, '\'');
501 	  if (!p)
502 	    goto done;
503 
504 	  /* Find the closing quote.  */
505 	  q = strchr (p + 1, '\'');
506 	  if (!q)
507 	    goto done;
508 
509 	  obstack_grow (&arg_stack, p + 1, q - (p + 1));
510 
511 	  /* Replace '\'' with '.  This is how set_collect_gcc_options
512 	     encodes a single-quote.  */
513 	  while (q[1] == '\\' && q[2] == '\'' && q[3] == '\'')
514 	    {
515 	      const char *r;
516 
517 	      r = strchr (q + 4, '\'');
518 	      if (!r)
519 		goto done;
520 
521 	      obstack_grow (&arg_stack, q + 3, r - (q + 3));
522 	      q = r;
523 	    }
524 
525 	  obstack_1grow (&arg_stack, '\0');
526 	  obstack_ptr_grow (&temporary_obstack, obstack_finish (&arg_stack));
527 	}
528     done:
529       obstack_ptr_grow (&temporary_obstack, f->main);
530       obstack_ptr_grow (&temporary_obstack, NULL);
531       argv = XOBFINISH (&temporary_obstack, char **);
532 
533       if (tlink_verbose)
534 	fprintf (stderr, _("collect: recompiling %s\n"), f->main);
535 
536       if (chdir (f->dir) != 0
537 	  || tlink_execute (c_file_name, argv, NULL, NULL) != 0
538 	  || chdir (initial_cwd) != 0)
539 	return 0;
540 
541       read_repo_file (f);
542 
543       obstack_free (&arg_stack, NULL);
544       obstack_free (&temporary_obstack, temporary_firstobj);
545     }
546   return 1;
547 }
548 
549 /* The first phase of processing: determine which object files have
550    .rpo files associated with them, and read in the information.  */
551 
552 static int
read_repo_files(char ** object_lst)553 read_repo_files (char **object_lst)
554 {
555   char **object = object_lst;
556 
557   for (; *object; object++)
558     {
559       const char *p;
560       file *f;
561 
562       /* Don't bother trying for ld flags.  */
563       if (*object[0] == '-')
564 	continue;
565 
566       p = frob_extension (*object, ".rpo");
567 
568       if (! file_exists (p))
569 	continue;
570 
571       f = file_hash_lookup (p);
572 
573       read_repo_file (f);
574     }
575 
576   if (file_stack != NULL && ! recompile_files ())
577     return 0;
578 
579   return (symbol_stack != NULL);
580 }
581 
582 /* Add the demangled forms of any new symbols to the hash table.  */
583 
584 static void
demangle_new_symbols(void)585 demangle_new_symbols (void)
586 {
587   symbol *sym;
588 
589   while ((sym = symbol_pop ()) != NULL)
590     {
591       demangled *dem;
592       const char *p = cplus_demangle (sym->key, DMGL_PARAMS | DMGL_ANSI);
593 
594       if (! p)
595 	continue;
596 
597       dem = demangled_hash_lookup (p, true);
598       dem->mangled = sym->key;
599     }
600 }
601 
602 /* Step through the output of the linker, in the file named FNAME, and
603    adjust the settings for each symbol encountered.  */
604 
605 static int
scan_linker_output(const char * fname)606 scan_linker_output (const char *fname)
607 {
608   FILE *stream = fopen (fname, "r");
609   char *line;
610   int skip_next_in_line = 0;
611 
612   while ((line = tfgets (stream)) != NULL)
613     {
614       char *p = line, *q;
615       symbol *sym;
616       int end;
617       int ok = 0;
618 
619       /* On darwin9, we might have to skip " in " lines as well.  */
620       if (skip_next_in_line
621 	  && strstr (p, " in "))
622 	  continue;
623       skip_next_in_line = 0;
624 
625       while (*p && ISSPACE ((unsigned char) *p))
626 	++p;
627 
628       if (! *p)
629 	continue;
630 
631       for (q = p; *q && ! ISSPACE ((unsigned char) *q); ++q)
632 	;
633 
634       /* Try the first word on the line.  */
635       if (*p == '.')
636 	++p;
637       if (!strncmp (p, USER_LABEL_PREFIX, strlen (USER_LABEL_PREFIX)))
638 	p += strlen (USER_LABEL_PREFIX);
639 
640       end = ! *q;
641       *q = 0;
642       sym = symbol_hash_lookup (p, false);
643 
644       /* Some SVR4 linkers produce messages like
645 	 ld: 0711-317 ERROR: Undefined symbol: .g__t3foo1Zi
646 	 */
647       if (! sym && ! end && strstr (q + 1, "Undefined symbol: "))
648 	{
649 	  char *p = strrchr (q + 1, ' ');
650 	  p++;
651 	  if (*p == '.')
652 	    p++;
653 	  if (!strncmp (p, USER_LABEL_PREFIX, strlen (USER_LABEL_PREFIX)))
654 	    p += strlen (USER_LABEL_PREFIX);
655 	  sym = symbol_hash_lookup (p, false);
656 	}
657 
658       if (! sym && ! end)
659 	/* Try a mangled name in quotes.  */
660 	{
661 	  const char *oldq = q + 1;
662 	  demangled *dem = 0;
663 	  q = 0;
664 
665 	  /* On darwin9, we look for "foo" referenced from:\n\(.* in .*\n\)*  */
666 	  if (strcmp (oldq, "referenced from:") == 0)
667 	    {
668 	      /* We have to remember that we found a symbol to tweak.  */
669 	      ok = 1;
670 
671 	      /* We actually want to start from the first word on the
672 		 line.  */
673 	      oldq = p;
674 
675 	      /* Since the format is multiline, we have to skip
676 		 following lines with " in ".  */
677 	      skip_next_in_line = 1;
678 	    }
679 
680 	  /* First try `GNU style'.  */
681 	  p = strchr (oldq, '`');
682 	  if (p)
683 	    p++, q = strchr (p, '\'');
684 	  /* Then try "double quotes".  */
685 	  else if (p = strchr (oldq, '"'), p)
686 	    p++, q = strchr (p, '"');
687 	  else {
688 	    /* Then try entire line.  */
689 	    q = strchr (oldq, 0);
690 	    if (q != oldq)
691 	      p = (char *)oldq;
692 	  }
693 
694 	  if (p)
695 	    {
696 	      /* Don't let the strstr's below see the demangled name; we
697 		 might get spurious matches.  */
698 	      p[-1] = '\0';
699 
700 	      /* powerpc64-linux references .foo when calling function foo.  */
701 	      if (*p == '.')
702 		p++;
703 	    }
704 
705 	  /* We need to check for certain error keywords here, or we would
706 	     mistakenly use GNU ld's "In function `foo':" message.  */
707 	  if (q && (ok
708 		    || strstr (oldq, "ndefined")
709 		    || strstr (oldq, "nresolved")
710 		    || strstr (oldq, "nsatisfied")
711 		    || strstr (oldq, "ultiple")))
712 	    {
713 	      *q = 0;
714 	      dem = demangled_hash_lookup (p, false);
715 	      if (dem)
716 		sym = symbol_hash_lookup (dem->mangled, false);
717 	      else
718 		{
719 		  if (!strncmp (p, USER_LABEL_PREFIX,
720 				strlen (USER_LABEL_PREFIX)))
721 		    p += strlen (USER_LABEL_PREFIX);
722 		  sym = symbol_hash_lookup (p, false);
723 		}
724 	    }
725 	}
726 
727       if (sym && sym->tweaked)
728 	{
729 	  error ("'%s' was assigned to '%s', but was not defined "
730 		 "during recompilation, or vice versa",
731 		 sym->key, sym->file->key);
732 	  fclose (stream);
733 	  return 0;
734 	}
735       if (sym && !sym->tweaking)
736 	{
737 	  if (tlink_verbose >= 2)
738 	    fprintf (stderr, _("collect: tweaking %s in %s\n"),
739 		     sym->key, sym->file->key);
740 	  sym->tweaking = 1;
741 	  file_push (sym->file);
742 	}
743 
744       obstack_free (&temporary_obstack, temporary_firstobj);
745     }
746 
747   fclose (stream);
748   return (file_stack != NULL);
749 }
750 
751 /* Entry point for tlink.  Called from main in collect2.c.
752 
753    Iteratively try to provide definitions for all the unresolved symbols
754    mentioned in the linker error messages.
755 
756    LD_ARGV is an array of arguments for the linker.
757    OBJECT_LST is an array of object files that we may be able to recompile
758      to provide missing definitions.  Currently ignored.  */
759 
760 void
do_tlink(char ** ld_argv,char ** object_lst ATTRIBUTE_UNUSED)761 do_tlink (char **ld_argv, char **object_lst ATTRIBUTE_UNUSED)
762 {
763   int exit = tlink_execute ("ld", ld_argv, ldout, lderrout);
764 
765   tlink_init ();
766 
767   if (exit)
768     {
769       int i = 0;
770 
771       /* Until collect does a better job of figuring out which are object
772 	 files, assume that everything on the command line could be.  */
773       if (read_repo_files (ld_argv))
774 	while (exit && i++ < MAX_ITERATIONS)
775 	  {
776 	    if (tlink_verbose >= 3)
777 	      {
778 		dump_file (ldout, stdout);
779 		dump_file (lderrout, stderr);
780 	      }
781 	    demangle_new_symbols ();
782 	    if (! scan_linker_output (ldout)
783 		&& ! scan_linker_output (lderrout))
784 	      break;
785 	    if (! recompile_files ())
786 	      break;
787 	    if (tlink_verbose)
788 	      fprintf (stderr, _("collect: relinking\n"));
789 	    exit = tlink_execute ("ld", ld_argv, ldout, lderrout);
790 	  }
791     }
792 
793   dump_file (ldout, stdout);
794   unlink (ldout);
795   dump_file (lderrout, stderr);
796   unlink (lderrout);
797   if (exit)
798     {
799       error ("ld returned %d exit status", exit);
800       collect_exit (exit);
801     }
802 }
803