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