|
|
1.1 ! root 1: /* Collect static initialization info into data structures ! 2: that can be traversed by C++ initialization and finalization ! 3: routines. ! 4: ! 5: Copyright (C) 1992, 1993 Free Software Foundation, Inc. ! 6: Contributed by Chris Smith ([email protected]). ! 7: Heavily modified by Michael Meissner ([email protected]), ! 8: Per Bothner ([email protected]), and John Gilmore ([email protected]). ! 9: ! 10: This file is part of GNU CC. ! 11: ! 12: GNU CC is free software; you can redistribute it and/or modify ! 13: it under the terms of the GNU General Public License as published by ! 14: the Free Software Foundation; either version 2, or (at your option) ! 15: any later version. ! 16: ! 17: GNU CC is distributed in the hope that it will be useful, ! 18: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 19: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 20: GNU General Public License for more details. ! 21: ! 22: You should have received a copy of the GNU General Public License ! 23: along with GNU CC; see the file COPYING. If not, write to ! 24: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 25: ! 26: ! 27: /* Build tables of static constructors and destructors and run ld. */ ! 28: ! 29: #include <sys/types.h> ! 30: #include <stdio.h> ! 31: #include <ctype.h> ! 32: #include <errno.h> ! 33: #include <signal.h> ! 34: #include <sys/file.h> ! 35: #include <sys/stat.h> ! 36: #ifdef NO_WAIT_H ! 37: #include <sys/wait.h> ! 38: #endif ! 39: ! 40: #ifndef errno ! 41: extern int errno; ! 42: #endif ! 43: ! 44: #if defined(bsd4_4) ! 45: extern const char *const sys_errlist[]; ! 46: #else ! 47: extern char *sys_errlist[]; ! 48: #endif ! 49: extern int sys_nerr; ! 50: ! 51: #define COLLECT ! 52: ! 53: #include "config.h" ! 54: ! 55: #ifndef __STDC__ ! 56: #define generic char ! 57: #define const ! 58: ! 59: #else ! 60: #define generic void ! 61: #endif ! 62: ! 63: #ifdef USG ! 64: #define vfork fork ! 65: #endif ! 66: ! 67: /* Add prototype support. */ ! 68: #ifndef PROTO ! 69: #if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) ! 70: #define PROTO(ARGS) ARGS ! 71: #else ! 72: #define PROTO(ARGS) () ! 73: #endif ! 74: #endif ! 75: ! 76: #ifndef R_OK ! 77: #define R_OK 4 ! 78: #define W_OK 2 ! 79: #define X_OK 1 ! 80: #endif ! 81: ! 82: /* On MSDOS, write temp files in current dir ! 83: because there's no place else we can expect to use. */ ! 84: #if __MSDOS__ ! 85: #ifndef P_tmpdir ! 86: #define P_tmpdir "./" ! 87: #endif ! 88: #endif ! 89: ! 90: /* On certain systems, we have code that works by scanning the object file ! 91: directly. But this code uses system-specific header files and library ! 92: functions, so turn it off in a cross-compiler. Likewise, the names of ! 93: the utilities aren't correct for a cross-compiler; we have to hope that ! 94: cross-versions are in the proper directories. */ ! 95: ! 96: #ifdef CROSS_COMPILE ! 97: #undef OBJECT_FORMAT_COFF ! 98: #undef OBJECT_FORMAT_ROSE ! 99: #undef MD_EXEC_PREFIX ! 100: #undef REAL_LD_FILE_NAME ! 101: #undef REAL_NM_FILE_NAME ! 102: #undef REAL_STRIP_FILE_NAME ! 103: #endif ! 104: ! 105: /* If we can't use a special method, use the ordinary one: ! 106: run nm to find what symbols are present. ! 107: In a cross-compiler, this means you need a cross nm, ! 108: but that isn't quite as unpleasant as special headers. */ ! 109: ! 110: #if !defined (OBJECT_FORMAT_COFF) && !defined (OBJECT_FORMAT_ROSE) ! 111: #define OBJECT_FORMAT_NONE ! 112: #endif ! 113: ! 114: #ifdef OBJECT_FORMAT_COFF ! 115: ! 116: #include <a.out.h> ! 117: #include <ar.h> ! 118: ! 119: #ifdef UMAX ! 120: #include <sgs.h> ! 121: #endif ! 122: ! 123: /* Many versions of ldfcn.h define these. */ ! 124: #ifdef FREAD ! 125: #undef FREAD ! 126: #undef FWRITE ! 127: #endif ! 128: ! 129: #include <ldfcn.h> ! 130: ! 131: /* Some systems have an ISCOFF macro, but others do not. In some cases ! 132: the macro may be wrong. MY_ISCOFF is defined in tm.h files for machines ! 133: that either do not have an ISCOFF macro in /usr/include or for those ! 134: where it is wrong. */ ! 135: ! 136: #ifndef MY_ISCOFF ! 137: #define MY_ISCOFF(X) ISCOFF (X) ! 138: #endif ! 139: ! 140: #endif /* OBJECT_FORMAT_COFF */ ! 141: ! 142: #ifdef OBJECT_FORMAT_ROSE ! 143: ! 144: #ifdef _OSF_SOURCE ! 145: #define USE_MMAP ! 146: #endif ! 147: ! 148: #ifdef USE_MMAP ! 149: #include <sys/mman.h> ! 150: #endif ! 151: ! 152: #include <unistd.h> ! 153: #include <mach_o_format.h> ! 154: #include <mach_o_header.h> ! 155: #include <mach_o_vals.h> ! 156: #include <mach_o_types.h> ! 157: ! 158: #endif /* OBJECT_FORMAT_ROSE */ ! 159: ! 160: #ifdef OBJECT_FORMAT_NONE ! 161: ! 162: /* Default flags to pass to nm. */ ! 163: #ifndef NM_FLAGS ! 164: #define NM_FLAGS "-p" ! 165: #endif ! 166: ! 167: #endif /* OBJECT_FORMAT_NONE */ ! 168: ! 169: /* Some systems use __main in a way incompatible with its use in gcc, in these ! 170: cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to ! 171: give the same symbol without quotes for an alternative entry point. You ! 172: must define both, or niether. */ ! 173: #ifndef NAME__MAIN ! 174: #define NAME__MAIN "__main" ! 175: #define SYMBOL__MAIN __main ! 176: #endif ! 177: ! 178: ! 179: /* Linked lists of constructor and destructor names. */ ! 180: ! 181: struct id ! 182: { ! 183: struct id *next; ! 184: int sequence; ! 185: char name[1]; ! 186: }; ! 187: ! 188: struct head ! 189: { ! 190: struct id *first; ! 191: struct id *last; ! 192: int number; ! 193: }; ! 194: ! 195: /* Enumeration giving which pass this is for scanning the program file. */ ! 196: ! 197: enum pass { ! 198: PASS_FIRST, /* without constructors */ ! 199: PASS_SECOND /* with constructors linked in */ ! 200: }; ! 201: ! 202: #ifndef NO_SYS_SIGLIST ! 203: extern char *sys_siglist[]; ! 204: #endif ! 205: extern char *version_string; ! 206: ! 207: static int vflag; /* true if -v */ ! 208: static int rflag; /* true if -r */ ! 209: static int strip_flag; /* true if -s */ ! 210: ! 211: static int debug; /* true if -debug */ ! 212: ! 213: static int temp_filename_length; /* Length of temp_filename */ ! 214: static char *temp_filename; /* Base of temp filenames */ ! 215: static char *c_file; /* <xxx>.c for constructor/destructor list. */ ! 216: static char *o_file; /* <xxx>.o for constructor/destructor list. */ ! 217: static char *output_file; /* Output file for ld. */ ! 218: static char *nm_file_name; /* pathname of nm */ ! 219: static char *strip_file_name; /* pathname of strip */ ! 220: ! 221: static struct head constructors; /* list of constructors found */ ! 222: static struct head destructors; /* list of destructors found */ ! 223: ! 224: extern char *getenv (); ! 225: extern char *mktemp (); ! 226: extern FILE *fdopen (); ! 227: ! 228: /* Structure to hold all the directories in which to search for files to ! 229: execute. */ ! 230: ! 231: struct prefix_list ! 232: { ! 233: char *prefix; /* String to prepend to the path. */ ! 234: struct prefix_list *next; /* Next in linked list. */ ! 235: }; ! 236: ! 237: struct path_prefix ! 238: { ! 239: struct prefix_list *plist; /* List of prefixes to try */ ! 240: int max_len; /* Max length of a prefix in PLIST */ ! 241: char *name; /* Name of this list (used in config stuff) */ ! 242: }; ! 243: ! 244: static void my_exit PROTO((int)); ! 245: static void handler PROTO((int)); ! 246: static int is_ctor_dtor PROTO((char *)); ! 247: static void choose_temp_base PROTO((void)); ! 248: static int is_in_prefix_list PROTO((struct path_prefix *, char *, int)); ! 249: static char *find_a_file PROTO((struct path_prefix *, char *)); ! 250: static void add_prefix PROTO((struct path_prefix *, char *)); ! 251: static void prefix_from_env PROTO((char *, struct path_prefix *)); ! 252: static void do_wait PROTO((char *)); ! 253: static void fork_execute PROTO((char *, char **)); ! 254: static void maybe_unlink PROTO((char *)); ! 255: static void add_to_list PROTO((struct head *, char *)); ! 256: static void write_list PROTO((FILE *, char *, struct id *)); ! 257: static void write_list_with_asm PROTO((FILE *, char *, struct id *)); ! 258: static void write_c_file PROTO((FILE *, char *)); ! 259: static void scan_prog_file PROTO((char *, enum pass)); ! 260: ! 261: generic *xcalloc (); ! 262: generic *xmalloc (); ! 263: ! 264: extern char *index (); ! 265: extern char *rindex (); ! 266: ! 267: #ifdef NO_DUP2 ! 268: int ! 269: dup2 (oldfd, newfd) ! 270: int oldfd; ! 271: int newfd; ! 272: { ! 273: int fdtmp[256]; ! 274: int fdx = 0; ! 275: int fd; ! 276: ! 277: if (oldfd == newfd) ! 278: return 0; ! 279: close (newfd); ! 280: while ((fd = dup (oldfd)) != newfd) /* good enough for low fd's */ ! 281: fdtmp[fdx++] = fd; ! 282: while (fdx > 0) ! 283: close (fdtmp[--fdx]); ! 284: ! 285: return 0; ! 286: } ! 287: #endif ! 288: ! 289: char * ! 290: my_strerror (e) ! 291: int e; ! 292: { ! 293: static char buffer[30]; ! 294: ! 295: if (!e) ! 296: return ""; ! 297: ! 298: if (e > 0 && e < sys_nerr) ! 299: return sys_errlist[e]; ! 300: ! 301: sprintf (buffer, "Unknown error %d", e); ! 302: return buffer; ! 303: } ! 304: ! 305: /* Delete tempfiles and exit function. */ ! 306: ! 307: static void ! 308: my_exit (status) ! 309: int status; ! 310: { ! 311: if (c_file != 0 && c_file[0]) ! 312: maybe_unlink (c_file); ! 313: ! 314: if (o_file != 0 && o_file[0]) ! 315: maybe_unlink (o_file); ! 316: ! 317: if (status != 0 && output_file != 0 && output_file[0]) ! 318: maybe_unlink (output_file); ! 319: ! 320: exit (status); ! 321: } ! 322: ! 323: ! 324: /* Die when sys call fails. */ ! 325: ! 326: static void ! 327: fatal_perror (string, arg1, arg2, arg3) ! 328: char *string; ! 329: { ! 330: int e = errno; ! 331: ! 332: fprintf (stderr, "collect2: "); ! 333: fprintf (stderr, string, arg1, arg2, arg3); ! 334: fprintf (stderr, ": %s\n", my_strerror (e)); ! 335: my_exit (1); ! 336: } ! 337: ! 338: /* Just die. */ ! 339: ! 340: static void ! 341: fatal (string, arg1, arg2, arg3) ! 342: char *string; ! 343: { ! 344: fprintf (stderr, "collect2: "); ! 345: fprintf (stderr, string, arg1, arg2, arg3); ! 346: fprintf (stderr, "\n"); ! 347: my_exit (1); ! 348: } ! 349: ! 350: /* Write error message. */ ! 351: ! 352: static void ! 353: error (string, arg1, arg2, arg3, arg4) ! 354: char *string; ! 355: { ! 356: fprintf (stderr, "collect2: "); ! 357: fprintf (stderr, string, arg1, arg2, arg3, arg4); ! 358: fprintf (stderr, "\n"); ! 359: } ! 360: ! 361: /* In case obstack is linked in, and abort is defined to fancy_abort, ! 362: provide a default entry. */ ! 363: ! 364: void ! 365: fancy_abort () ! 366: { ! 367: fatal ("internal error"); ! 368: } ! 369: ! 370: ! 371: static void ! 372: handler (signo) ! 373: int signo; ! 374: { ! 375: if (c_file != 0 && c_file[0]) ! 376: maybe_unlink (c_file); ! 377: ! 378: if (o_file != 0 && o_file[0]) ! 379: maybe_unlink (o_file); ! 380: ! 381: signal (signo, SIG_DFL); ! 382: kill (getpid (), signo); ! 383: } ! 384: ! 385: ! 386: generic * ! 387: xcalloc (size1, size2) ! 388: int size1, size2; ! 389: { ! 390: generic *ptr = (generic *) calloc (size1, size2); ! 391: if (ptr) ! 392: return ptr; ! 393: ! 394: fatal ("out of memory"); ! 395: return (generic *)0; ! 396: } ! 397: ! 398: generic * ! 399: xmalloc (size) ! 400: int size; ! 401: { ! 402: generic *ptr = (generic *) malloc (size); ! 403: if (ptr) ! 404: return ptr; ! 405: ! 406: fatal ("out of memory"); ! 407: return (generic *)0; ! 408: } ! 409: ! 410: /* Make a copy of a string INPUT with size SIZE. */ ! 411: ! 412: char * ! 413: savestring (input, size) ! 414: char *input; ! 415: int size; ! 416: { ! 417: char *output = (char *) xmalloc (size + 1); ! 418: bcopy (input, output, size); ! 419: output[size] = 0; ! 420: return output; ! 421: } ! 422: ! 423: /* Decide whether the given symbol is: ! 424: a constructor (1), a destructor (2), or neither (0). */ ! 425: ! 426: static int ! 427: is_ctor_dtor (s) ! 428: char *s; ! 429: { ! 430: struct names { char *name; int len; int ret; int two_underscores; }; ! 431: ! 432: register struct names *p; ! 433: register int ch; ! 434: register char *orig_s = s; ! 435: ! 436: static struct names special[] = { ! 437: #ifdef NO_DOLLAR_IN_LABEL ! 438: #ifdef NO_DOT_IN_LABEL ! 439: { "GLOBAL__I_", sizeof ("GLOBAL__I_")-1, 1, 0 }, ! 440: { "GLOBAL__D_", sizeof ("GLOBAL__D_")-1, 2, 0 }, ! 441: #else ! 442: { "GLOBAL_.I.", sizeof ("GLOBAL_.I.")-1, 1, 0 }, ! 443: { "GLOBAL_.D.", sizeof ("GLOBAL_.D.")-1, 2, 0 }, ! 444: #endif ! 445: #else ! 446: { "GLOBAL_$I$", sizeof ("GLOBAL_$I$")-1, 1, 0 }, ! 447: { "GLOBAL_$D$", sizeof ("GLOBAL_$D$")-1, 2, 0 }, ! 448: #endif ! 449: #ifdef CFRONT_LOSSAGE /* Don't collect cfront initialization functions. ! 450: cfront has its own linker procedure to collect them; ! 451: if collect2 gets them too, they get collected twice ! 452: when the cfront procedure is run and the compiler used ! 453: for linking happens to be GCC. */ ! 454: { "sti__", sizeof ("sti__")-1, 1, 1 }, ! 455: { "std__", sizeof ("std__")-1, 2, 1 }, ! 456: #endif /* CFRONT_LOSSAGE */ ! 457: { NULL, 0, 0, 0 } ! 458: }; ! 459: ! 460: while ((ch = *s) == '_') ! 461: ++s; ! 462: ! 463: if (s == orig_s) ! 464: return 0; ! 465: ! 466: for (p = &special[0]; p->len > 0; p++) ! 467: { ! 468: if (ch == p->name[0] ! 469: && (!p->two_underscores || ((s - orig_s) >= 2)) ! 470: && strncmp(s, p->name, p->len) == 0) ! 471: { ! 472: return p->ret; ! 473: } ! 474: } ! 475: return 0; ! 476: } ! 477: ! 478: ! 479: /* Compute a string to use as the base of all temporary file names. ! 480: It is substituted for %g. */ ! 481: ! 482: static void ! 483: choose_temp_base () ! 484: { ! 485: char *base = getenv ("TMPDIR"); ! 486: int len; ! 487: ! 488: if (base == (char *)0) ! 489: { ! 490: #ifdef P_tmpdir ! 491: if (access (P_tmpdir, R_OK | W_OK) == 0) ! 492: base = P_tmpdir; ! 493: #endif ! 494: if (base == (char *)0) ! 495: { ! 496: if (access ("/usr/tmp", R_OK | W_OK) == 0) ! 497: base = "/usr/tmp/"; ! 498: else ! 499: base = "/tmp/"; ! 500: } ! 501: } ! 502: ! 503: len = strlen (base); ! 504: temp_filename = xmalloc (len + sizeof("/ccXXXXXX") + 1); ! 505: strcpy (temp_filename, base); ! 506: if (len > 0 && temp_filename[len-1] != '/') ! 507: temp_filename[len++] = '/'; ! 508: strcpy (temp_filename + len, "ccXXXXXX"); ! 509: ! 510: mktemp (temp_filename); ! 511: temp_filename_length = strlen (temp_filename); ! 512: } ! 513: ! 514: /* Routine to add variables to the environment. */ ! 515: ! 516: #ifndef HAVE_PUTENV ! 517: ! 518: int ! 519: putenv (str) ! 520: char *str; ! 521: { ! 522: #ifndef VMS /* nor about VMS */ ! 523: ! 524: extern char **environ; ! 525: char **old_environ = environ; ! 526: char **envp; ! 527: int num_envs = 0; ! 528: int name_len = 1; ! 529: int str_len = strlen (str); ! 530: char *p = str; ! 531: int ch; ! 532: ! 533: while ((ch = *p++) != '\0' && ch != '=') ! 534: name_len++; ! 535: ! 536: if (!ch) ! 537: abort (); ! 538: ! 539: /* Search for replacing an existing environment variable, and ! 540: count the number of total environment variables. */ ! 541: for (envp = old_environ; *envp; envp++) ! 542: { ! 543: num_envs++; ! 544: if (!strncmp (str, *envp, name_len)) ! 545: { ! 546: *envp = str; ! 547: return 0; ! 548: } ! 549: } ! 550: ! 551: /* Add a new environment variable */ ! 552: environ = (char **) xmalloc (sizeof (char *) * (num_envs+2)); ! 553: *environ = str; ! 554: bcopy (old_environ, environ+1, sizeof (char *) * (num_envs+1)); ! 555: return 0; ! 556: #endif /* VMS */ ! 557: } ! 558: ! 559: #endif /* HAVE_PUTENV */ ! 560: ! 561: /* By default, colon separates directories in a path. */ ! 562: #ifndef PATH_SEPARATOR ! 563: #define PATH_SEPARATOR ':' ! 564: #endif ! 565: ! 566: /* We maintain two prefix lists: one from COMPILER_PATH environment variable ! 567: and one from the PATH variable. */ ! 568: ! 569: static struct path_prefix cpath, path; ! 570: ! 571: #ifdef CROSS_COMPILE ! 572: /* This is the name of the target machine. We use it to form the name ! 573: of the files to execute. */ ! 574: ! 575: static char *target_machine = TARGET_MACHINE; ! 576: #endif ! 577: ! 578: /* Names under which we were executed. Never return one of those files in our ! 579: searches. */ ! 580: ! 581: static struct path_prefix our_file_names; ! 582: ! 583: /* Determine if STRING is in PPREFIX. ! 584: ! 585: This utility is currently only used to look up file names. Prefix lists ! 586: record directory names. This matters to us because the latter has a ! 587: trailing slash, so I've added a flag to handle both. */ ! 588: ! 589: static int ! 590: is_in_prefix_list (pprefix, string, filep) ! 591: struct path_prefix *pprefix; ! 592: char *string; ! 593: int filep; ! 594: { ! 595: struct prefix_list *pl; ! 596: ! 597: if (filep) ! 598: { ! 599: int len = strlen (string); ! 600: ! 601: for (pl = pprefix->plist; pl; pl = pl->next) ! 602: { ! 603: if (strncmp (pl->prefix, string, len) == 0 ! 604: && strcmp (pl->prefix + len, "/") == 0) ! 605: return 1; ! 606: } ! 607: } ! 608: else ! 609: { ! 610: for (pl = pprefix->plist; pl; pl = pl->next) ! 611: { ! 612: if (strcmp (pl->prefix, string) == 0) ! 613: return 1; ! 614: } ! 615: } ! 616: ! 617: return 0; ! 618: } ! 619: ! 620: /* Search for NAME using prefix list PPREFIX. We only look for executable ! 621: files. ! 622: ! 623: Return 0 if not found, otherwise return its name, allocated with malloc. */ ! 624: ! 625: static char * ! 626: find_a_file (pprefix, name) ! 627: struct path_prefix *pprefix; ! 628: char *name; ! 629: { ! 630: char *temp; ! 631: struct prefix_list *pl; ! 632: int len = pprefix->max_len + strlen (name) + 1; ! 633: ! 634: #ifdef EXECUTABLE_SUFFIX ! 635: len += strlen (EXECUTABLE_SUFFIX); ! 636: #endif ! 637: ! 638: temp = xmalloc (len); ! 639: ! 640: /* Determine the filename to execute (special case for absolute paths). */ ! 641: ! 642: if (*name == '/') ! 643: { ! 644: if (access (name, X_OK) == 0) ! 645: { ! 646: strcpy (temp, name); ! 647: return temp; ! 648: } ! 649: } ! 650: else ! 651: for (pl = pprefix->plist; pl; pl = pl->next) ! 652: { ! 653: strcpy (temp, pl->prefix); ! 654: strcat (temp, name); ! 655: if (! is_in_prefix_list (&our_file_names, temp, 1) ! 656: /* This is a kludge, but there seems no way around it. */ ! 657: && strcmp (temp, "./ld") != 0 ! 658: && access (temp, X_OK) == 0) ! 659: return temp; ! 660: ! 661: #ifdef EXECUTABLE_SUFFIX ! 662: /* Some systems have a suffix for executable files. ! 663: So try appending that. */ ! 664: strcat (temp, EXECUTABLE_SUFFIX); ! 665: if (! is_in_prefix_list (&our_file_names, temp, 1) ! 666: && access (temp, X_OK) == 0) ! 667: return temp; ! 668: #endif ! 669: } ! 670: ! 671: free (temp); ! 672: return 0; ! 673: } ! 674: ! 675: /* Add an entry for PREFIX to prefix list PPREFIX. */ ! 676: ! 677: static void ! 678: add_prefix (pprefix, prefix) ! 679: struct path_prefix *pprefix; ! 680: char *prefix; ! 681: { ! 682: struct prefix_list *pl, **prev; ! 683: int len; ! 684: ! 685: if (pprefix->plist) ! 686: { ! 687: for (pl = pprefix->plist; pl->next; pl = pl->next) ! 688: ; ! 689: prev = &pl->next; ! 690: } ! 691: else ! 692: prev = &pprefix->plist; ! 693: ! 694: /* Keep track of the longest prefix */ ! 695: ! 696: len = strlen (prefix); ! 697: if (len > pprefix->max_len) ! 698: pprefix->max_len = len; ! 699: ! 700: pl = (struct prefix_list *) xmalloc (sizeof (struct prefix_list)); ! 701: pl->prefix = savestring (prefix, len); ! 702: ! 703: if (*prev) ! 704: pl->next = *prev; ! 705: else ! 706: pl->next = (struct prefix_list *) 0; ! 707: *prev = pl; ! 708: } ! 709: ! 710: /* Take the value of the environment variable ENV, break it into a path, and ! 711: add of the entries to PPREFIX. */ ! 712: ! 713: static void ! 714: prefix_from_env (env, pprefix) ! 715: char *env; ! 716: struct path_prefix *pprefix; ! 717: { ! 718: char *p = getenv (env); ! 719: ! 720: if (p) ! 721: { ! 722: char *startp, *endp; ! 723: char *nstore = (char *) xmalloc (strlen (p) + 3); ! 724: ! 725: startp = endp = p; ! 726: while (1) ! 727: { ! 728: if (*endp == PATH_SEPARATOR || *endp == 0) ! 729: { ! 730: strncpy (nstore, startp, endp-startp); ! 731: if (endp == startp) ! 732: { ! 733: strcpy (nstore, "./"); ! 734: } ! 735: else if (endp[-1] != '/') ! 736: { ! 737: nstore[endp-startp] = '/'; ! 738: nstore[endp-startp+1] = 0; ! 739: } ! 740: else ! 741: nstore[endp-startp] = 0; ! 742: ! 743: add_prefix (pprefix, nstore); ! 744: if (*endp == 0) ! 745: break; ! 746: endp = startp = endp + 1; ! 747: } ! 748: else ! 749: endp++; ! 750: } ! 751: } ! 752: } ! 753: ! 754: /* Main program. */ ! 755: ! 756: int ! 757: main (argc, argv) ! 758: int argc; ! 759: char *argv[]; ! 760: { ! 761: char *ld_suffix = "ld"; ! 762: char *full_ld_suffix = ld_suffix; ! 763: char *real_ld_suffix = "real-ld"; ! 764: char *full_real_ld_suffix = real_ld_suffix; ! 765: #if 0 ! 766: char *gld_suffix = "gld"; ! 767: char *full_gld_suffix = gld_suffix; ! 768: #endif ! 769: char *nm_suffix = "nm"; ! 770: char *full_nm_suffix = nm_suffix; ! 771: char *gnm_suffix = "gnm"; ! 772: char *full_gnm_suffix = gnm_suffix; ! 773: char *strip_suffix = "strip"; ! 774: char *full_strip_suffix = strip_suffix; ! 775: char *gstrip_suffix = "gstrip"; ! 776: char *full_gstrip_suffix = gstrip_suffix; ! 777: char *arg; ! 778: FILE *outf; ! 779: char *ld_file_name; ! 780: char *c_file_name; ! 781: char *collect_name; ! 782: char *collect_names; ! 783: char *p; ! 784: char **c_argv; ! 785: char **c_ptr; ! 786: char **ld1_argv = (char **) xcalloc (sizeof (char *), argc+2); ! 787: char **ld1 = ld1_argv; ! 788: char **ld2_argv = (char **) xcalloc (sizeof (char *), argc+5); ! 789: char **ld2 = ld2_argv; ! 790: int first_file; ! 791: int num_c_args = argc+7; ! 792: int len; ! 793: int clen; ! 794: ! 795: #ifdef DEBUG ! 796: debug = 1; ! 797: vflag = 1; ! 798: #endif ! 799: ! 800: output_file = "a.out"; ! 801: ! 802: /* We must check that we do not call ourselves in an infinite ! 803: recursion loop. We append the name used for us to the COLLECT_NAMES ! 804: environment variable. ! 805: ! 806: In practice, collect will rarely invoke itself. This can happen now ! 807: that we are no longer called gld. A perfect example is when running ! 808: gcc in a build directory that has been installed. When looking for ! 809: ld's, we'll find our installed version and believe that's the real ld. */ ! 810: ! 811: /* We must also append COLLECT_NAME to COLLECT_NAMES to watch for the ! 812: previous version of collect (the one that used COLLECT_NAME and only ! 813: handled two levels of recursion). If we don't we may mutually recurse ! 814: forever. This can happen (I think) when bootstrapping the old version ! 815: and a new one is installed (rare, but we should handle it). ! 816: ??? Hopefully references to COLLECT_NAME can be removed at some point. */ ! 817: ! 818: collect_name = (char *) getenv ("COLLECT_NAME"); ! 819: collect_names = (char *) getenv ("COLLECT_NAMES"); ! 820: ! 821: p = (char *) xmalloc (strlen ("COLLECT_NAMES=") ! 822: + (collect_name ? strlen (collect_name) + 1 : 0) ! 823: + (collect_names ? strlen (collect_names) + 1 : 0) ! 824: + strlen (argv[0]) + 1); ! 825: strcpy (p, "COLLECT_NAMES="); ! 826: if (collect_name != 0) ! 827: sprintf (p + strlen (p), "%s%c", collect_name, PATH_SEPARATOR); ! 828: if (collect_names != 0) ! 829: sprintf (p + strlen (p), "%s%c", collect_names, PATH_SEPARATOR); ! 830: strcat (p, argv[0]); ! 831: putenv (p); ! 832: ! 833: prefix_from_env ("COLLECT_NAMES", &our_file_names); ! 834: ! 835: /* Set environment variable COLLECT_NAME to our name so the previous version ! 836: of collect won't find us. If it does we'll mutually recurse forever. ! 837: This can happen when bootstrapping the new version and an old version is ! 838: installed. ! 839: ??? Hopefully this bit of code can be removed at some point. */ ! 840: ! 841: p = xmalloc (strlen ("COLLECT_NAME=") + strlen (argv[0]) + 1); ! 842: sprintf (p, "COLLECT_NAME=%s", argv[0]); ! 843: putenv (p); ! 844: ! 845: p = (char *) getenv ("COLLECT_GCC_OPTIONS"); ! 846: if (p) ! 847: while (*p) ! 848: { ! 849: char *q = p; ! 850: while (*q && *q != ' ') q++; ! 851: if (*p == '-' && p[1] == 'm') ! 852: num_c_args++; ! 853: ! 854: if (*q) q++; ! 855: p = q; ! 856: } ! 857: ! 858: c_ptr = c_argv = (char **) xcalloc (sizeof (char *), num_c_args); ! 859: ! 860: if (argc < 2) ! 861: fatal ("no arguments"); ! 862: ! 863: #ifdef SIGQUIT ! 864: if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) ! 865: signal (SIGQUIT, handler); ! 866: #endif ! 867: if (signal (SIGINT, SIG_IGN) != SIG_IGN) ! 868: signal (SIGINT, handler); ! 869: #ifdef SIGALRM ! 870: if (signal (SIGALRM, SIG_IGN) != SIG_IGN) ! 871: signal (SIGALRM, handler); ! 872: #endif ! 873: #ifdef SIGHUP ! 874: if (signal (SIGHUP, SIG_IGN) != SIG_IGN) ! 875: signal (SIGHUP, handler); ! 876: #endif ! 877: if (signal (SIGSEGV, SIG_IGN) != SIG_IGN) ! 878: signal (SIGSEGV, handler); ! 879: #ifdef SIGBUS ! 880: if (signal (SIGBUS, SIG_IGN) != SIG_IGN) ! 881: signal (SIGBUS, handler); ! 882: #endif ! 883: ! 884: /* Extract COMPILER_PATH and PATH into our prefix list. */ ! 885: prefix_from_env ("COMPILER_PATH", &cpath); ! 886: prefix_from_env ("PATH", &path); ! 887: ! 888: #ifdef CROSS_COMPILE ! 889: /* If we look for a program in the compiler directories, we just use ! 890: the short name, since these directories are already system-specific. ! 891: But it we look for a took in the system directories, we need to ! 892: qualify the program name with the target machine. */ ! 893: ! 894: full_ld_suffix ! 895: = xcalloc (strlen (ld_suffix) + strlen (target_machine) + 2, 1); ! 896: strcpy (full_ld_suffix, target_machine); ! 897: strcat (full_ld_suffix, "-"); ! 898: strcat (full_ld_suffix, ld_suffix); ! 899: ! 900: full_real_ld_suffix ! 901: = xcalloc (strlen (real_ld_suffix) + strlen (target_machine) + 2, 1); ! 902: strcpy (full_real_ld_suffix, target_machine); ! 903: strcat (full_real_ld_suffix, "-"); ! 904: strcat (full_real_ld_suffix, real_ld_suffix); ! 905: ! 906: #if 0 ! 907: full_gld_suffix ! 908: = xcalloc (strlen (gld_suffix) + strlen (target_machine) + 2, 1); ! 909: strcpy (full_gld_suffix, target_machine); ! 910: strcat (full_gld_suffix, "-"); ! 911: strcat (full_gld_suffix, gld_suffix); ! 912: #endif ! 913: ! 914: full_nm_suffix ! 915: = xcalloc (strlen (nm_suffix) + strlen (target_machine) + 2, 1); ! 916: strcpy (full_nm_suffix, target_machine); ! 917: strcat (full_nm_suffix, "-"); ! 918: strcat (full_nm_suffix, nm_suffix); ! 919: ! 920: full_gnm_suffix ! 921: = xcalloc (strlen (gnm_suffix) + strlen (target_machine) + 2, 1); ! 922: strcpy (full_gnm_suffix, target_machine); ! 923: strcat (full_gnm_suffix, "-"); ! 924: strcat (full_gnm_suffix, gnm_suffix); ! 925: ! 926: full_strip_suffix ! 927: = xcalloc (strlen (strip_suffix) + strlen (target_machine) + 2, 1); ! 928: strcpy (full_strip_suffix, target_machine); ! 929: strcat (full_strip_suffix, "-"); ! 930: strcat (full_strip_suffix, strip_suffix); ! 931: ! 932: full_gstrip_suffix ! 933: = xcalloc (strlen (gstrip_suffix) + strlen (target_machine) + 2, 1); ! 934: strcpy (full_gstrip_suffix, target_machine); ! 935: strcat (full_gstrip_suffix, "-"); ! 936: strcat (full_gstrip_suffix, gstrip_suffix); ! 937: #endif /* CROSS_COMPILE */ ! 938: ! 939: /* Try to discover a valid linker/nm/strip to use. */ ! 940: ! 941: #if 0 ! 942: /* Search the (target-specific) compiler dirs for `gld'. */ ! 943: ld_file_name = find_a_file (&cpath, gld_suffix); ! 944: /* Search the ordinary system bin directories ! 945: for `gld' (if native linking) or `TARGET-gld' (if cross). */ ! 946: if (ld_file_name == 0) ! 947: ld_file_name = find_a_file (&path, full_gld_suffix); ! 948: #else ! 949: ld_file_name = 0; ! 950: #endif ! 951: /* Likewise for `real-ld'. */ ! 952: if (ld_file_name == 0) ! 953: ld_file_name = find_a_file (&cpath, real_ld_suffix); ! 954: if (ld_file_name == 0) ! 955: ld_file_name = find_a_file (&path, full_real_ld_suffix); ! 956: /* Maybe we know the right file to use (if not cross). */ ! 957: #ifdef REAL_LD_FILE_NAME ! 958: if (ld_file_name == 0) ! 959: ld_file_name = find_a_file (&path, REAL_LD_FILE_NAME); ! 960: #endif ! 961: if (ld_file_name == 0) ! 962: ld_file_name = find_a_file (&cpath, full_ld_suffix); ! 963: /* Search the ordinary system bin directories ! 964: for `ld' (if native linking) or `TARGET-ld' (if cross). */ ! 965: if (ld_file_name == 0) ! 966: ld_file_name = find_a_file (&path, full_ld_suffix); ! 967: ! 968: /* If we've invoked ourselves, try again with LD_FILE_NAME. */ ! 969: ! 970: if (collect_names != 0) ! 971: { ! 972: if (ld_file_name != 0) ! 973: { ! 974: argv[0] = ld_file_name; ! 975: execvp (argv[0], argv); ! 976: } ! 977: fatal ("cannot find `ld'"); ! 978: } ! 979: ! 980: nm_file_name = find_a_file (&cpath, gnm_suffix); ! 981: if (nm_file_name == 0) ! 982: nm_file_name = find_a_file (&path, full_gnm_suffix); ! 983: if (nm_file_name == 0) ! 984: nm_file_name = find_a_file (&cpath, nm_suffix); ! 985: #ifdef REAL_NM_FILE_NAME ! 986: if (nm_file_name == 0) ! 987: nm_file_name = find_a_file (&path, REAL_NM_FILE_NAME); ! 988: #endif ! 989: if (nm_file_name == 0) ! 990: nm_file_name = find_a_file (&path, full_nm_suffix); ! 991: ! 992: strip_file_name = find_a_file (&cpath, gstrip_suffix); ! 993: if (strip_file_name == 0) ! 994: strip_file_name = find_a_file (&path, full_gstrip_suffix); ! 995: if (strip_file_name == 0) ! 996: strip_file_name = find_a_file (&cpath, strip_suffix); ! 997: #ifdef REAL_STRIP_FILE_NAME ! 998: if (strip_file_name == 0) ! 999: strip_file_name = find_a_file (&path, REAL_STRIP_FILE_NAME); ! 1000: #endif ! 1001: if (strip_file_name == 0) ! 1002: strip_file_name = find_a_file (&path, full_strip_suffix); ! 1003: ! 1004: /* Determine the full path name of the C compiler to use. */ ! 1005: c_file_name = getenv ("COLLECT_GCC"); ! 1006: if (c_file_name == 0) ! 1007: { ! 1008: #ifdef CROSS_COMPILE ! 1009: c_file_name = xcalloc (sizeof ("gcc-") + strlen (target_machine) + 1, 1); ! 1010: strcpy (c_file_name, target_machine); ! 1011: strcat (c_file_name, "-gcc"); ! 1012: #else ! 1013: c_file_name = "gcc"; ! 1014: #endif ! 1015: } ! 1016: ! 1017: p = find_a_file (&cpath, c_file_name); ! 1018: ! 1019: /* Here it should be safe to use the system search path since we should have ! 1020: already qualified the name of the compiler when it is needed. */ ! 1021: if (p == 0) ! 1022: p = find_a_file (&path, c_file_name); ! 1023: ! 1024: if (p) ! 1025: c_file_name = p; ! 1026: ! 1027: *ld1++ = *ld2++ = ld_file_name; ! 1028: ! 1029: /* Make temp file names. */ ! 1030: choose_temp_base (); ! 1031: c_file = xcalloc (temp_filename_length + sizeof (".c"), 1); ! 1032: o_file = xcalloc (temp_filename_length + sizeof (".o"), 1); ! 1033: sprintf (c_file, "%s.c", temp_filename); ! 1034: sprintf (o_file, "%s.o", temp_filename); ! 1035: *c_ptr++ = c_file_name; ! 1036: *c_ptr++ = "-c"; ! 1037: *c_ptr++ = "-o"; ! 1038: *c_ptr++ = o_file; ! 1039: ! 1040: /* !!! When GCC calls collect2, ! 1041: it does not know whether it is calling collect2 or ld. ! 1042: So collect2 cannot meaningfully understand any options ! 1043: except those ld understands. ! 1044: If you propose to make GCC pass some other option, ! 1045: just imagine what will happen if ld is really ld!!! */ ! 1046: ! 1047: /* Parse arguments. Remember output file spec, pass the rest to ld. */ ! 1048: /* After the first file, put in the c++ rt0. */ ! 1049: ! 1050: first_file = 1; ! 1051: while ((arg = *++argv) != (char *)0) ! 1052: { ! 1053: *ld1++ = *ld2++ = arg; ! 1054: ! 1055: if (arg[0] == '-') ! 1056: switch (arg[1]) ! 1057: { ! 1058: case 'd': ! 1059: if (!strcmp (arg, "-debug")) ! 1060: { ! 1061: debug = 1; ! 1062: vflag = 1; ! 1063: ld1--; ! 1064: ld2--; ! 1065: } ! 1066: break; ! 1067: ! 1068: case 'o': ! 1069: output_file = (arg[2] == '\0') ? argv[1] : &arg[2]; ! 1070: break; ! 1071: ! 1072: case 'r': ! 1073: if (arg[2] == '\0') ! 1074: rflag = 1; ! 1075: break; ! 1076: ! 1077: case 's': ! 1078: if (arg[2] == '\0') ! 1079: { ! 1080: /* We must strip after the nm run, otherwise C++ linking ! 1081: won't work. Thus we strip in the second ld run, or ! 1082: else with strip if there is no second ld run. */ ! 1083: strip_flag = 1; ! 1084: ld1--; ! 1085: } ! 1086: break; ! 1087: ! 1088: case 'v': ! 1089: if (arg[2] == '\0') ! 1090: vflag = 1; ! 1091: break; ! 1092: } ! 1093: ! 1094: else if (first_file ! 1095: && (p = rindex (arg, '.')) != (char *)0 ! 1096: && strcmp (p, ".o") == 0) ! 1097: { ! 1098: first_file = 0; ! 1099: *ld2++ = o_file; ! 1100: } ! 1101: } ! 1102: ! 1103: /* Get any options that the upper GCC wants to pass to the sub-GCC. */ ! 1104: p = (char *) getenv ("COLLECT_GCC_OPTIONS"); ! 1105: if (p) ! 1106: while (*p) ! 1107: { ! 1108: char *q = p; ! 1109: while (*q && *q != ' ') q++; ! 1110: if (*p == '-' && (p[1] == 'm' || p[1] == 'f')) ! 1111: *c_ptr++ = savestring (p, q - p); ! 1112: ! 1113: if (*q) q++; ! 1114: p = q; ! 1115: } ! 1116: ! 1117: *c_ptr++ = c_file; ! 1118: *c_ptr = *ld1 = *ld2 = (char *)0; ! 1119: ! 1120: if (vflag) ! 1121: { ! 1122: fprintf (stderr, "collect2 version %s", version_string); ! 1123: #ifdef TARGET_VERSION ! 1124: TARGET_VERSION; ! 1125: #endif ! 1126: fprintf (stderr, "\n"); ! 1127: } ! 1128: ! 1129: if (debug) ! 1130: { ! 1131: char *ptr; ! 1132: fprintf (stderr, "ld_file_name = %s\n", ! 1133: (ld_file_name ? ld_file_name : "not found")); ! 1134: fprintf (stderr, "c_file_name = %s\n", ! 1135: (c_file_name ? c_file_name : "not found")); ! 1136: fprintf (stderr, "nm_file_name = %s\n", ! 1137: (nm_file_name ? nm_file_name : "not found")); ! 1138: fprintf (stderr, "strip_file_name = %s\n", ! 1139: (strip_file_name ? strip_file_name : "not found")); ! 1140: fprintf (stderr, "c_file = %s\n", ! 1141: (c_file ? c_file : "not found")); ! 1142: fprintf (stderr, "o_file = %s\n", ! 1143: (o_file ? o_file : "not found")); ! 1144: ! 1145: ptr = getenv ("COLLECT_NAMES"); ! 1146: if (ptr) ! 1147: fprintf (stderr, "COLLECT_NAMES = %s\n", ptr); ! 1148: ! 1149: ptr = getenv ("COLLECT_GCC_OPTIONS"); ! 1150: if (ptr) ! 1151: fprintf (stderr, "COLLECT_GCC_OPTIONS = %s\n", ptr); ! 1152: ! 1153: ptr = getenv ("COLLECT_GCC"); ! 1154: if (ptr) ! 1155: fprintf (stderr, "COLLECT_GCC = %s\n", ptr); ! 1156: ! 1157: ptr = getenv ("COMPILER_PATH"); ! 1158: if (ptr) ! 1159: fprintf (stderr, "COMPILER_PATH = %s\n", ptr); ! 1160: ! 1161: ptr = getenv ("LIBRARY_PATH"); ! 1162: if (ptr) ! 1163: fprintf (stderr, "LIBRARY_PATH = %s\n", ptr); ! 1164: ! 1165: fprintf (stderr, "\n"); ! 1166: } ! 1167: ! 1168: /* Load the program, searching all libraries. ! 1169: Examine the namelist with nm and search it for static constructors ! 1170: and destructors to call. ! 1171: Write the constructor and destructor tables to a .s file and reload. */ ! 1172: ! 1173: fork_execute ("ld", ld1_argv); ! 1174: ! 1175: /* If -r, don't build the constructor or destructor list, just return now. */ ! 1176: if (rflag) ! 1177: return 0; ! 1178: ! 1179: scan_prog_file (output_file, PASS_FIRST); ! 1180: ! 1181: if (debug) ! 1182: { ! 1183: fprintf (stderr, "%d constructor(s) found\n", constructors.number); ! 1184: fprintf (stderr, "%d destructor(s) found\n", destructors.number); ! 1185: } ! 1186: ! 1187: if (constructors.number == 0 && destructors.number == 0) ! 1188: { ! 1189: /* Strip now if it was requested on the command line. */ ! 1190: if (strip_flag) ! 1191: { ! 1192: char **strip_argv = (char **) xcalloc (sizeof (char *), 3); ! 1193: strip_argv[0] = strip_file_name; ! 1194: strip_argv[1] = output_file; ! 1195: strip_argv[2] = (char *) 0; ! 1196: fork_execute ("strip", strip_argv); ! 1197: } ! 1198: return 0; ! 1199: } ! 1200: ! 1201: outf = fopen (c_file, "w"); ! 1202: if (outf == (FILE *)0) ! 1203: fatal_perror ("%s", c_file); ! 1204: ! 1205: write_c_file (outf, c_file); ! 1206: ! 1207: if (fclose (outf)) ! 1208: fatal_perror ("closing %s", c_file); ! 1209: ! 1210: if (debug) ! 1211: { ! 1212: fprintf (stderr, "\n========== output_file = %s, c_file = %s\n", ! 1213: output_file, c_file); ! 1214: write_c_file (stderr, "stderr"); ! 1215: fprintf (stderr, "========== end of c_file\n\n"); ! 1216: } ! 1217: ! 1218: /* Assemble the constructor and destructor tables. ! 1219: Link the tables in with the rest of the program. */ ! 1220: ! 1221: fork_execute ("gcc", c_argv); ! 1222: fork_execute ("ld", ld2_argv); ! 1223: ! 1224: /* Let scan_prog_file do any final mods (OSF/rose needs this for ! 1225: constructors/destructors in shared libraries. */ ! 1226: scan_prog_file (output_file, PASS_SECOND); ! 1227: ! 1228: maybe_unlink (c_file); ! 1229: maybe_unlink (o_file); ! 1230: return 0; ! 1231: } ! 1232: ! 1233: ! 1234: /* Wait for a process to finish, and exit if a non-zero status is found. */ ! 1235: ! 1236: static void ! 1237: do_wait (prog) ! 1238: char *prog; ! 1239: { ! 1240: int status; ! 1241: ! 1242: wait (&status); ! 1243: if (status) ! 1244: { ! 1245: int sig = status & 0x7F; ! 1246: int ret; ! 1247: ! 1248: if (sig != -1 && sig != 0) ! 1249: { ! 1250: #ifdef NO_SYS_SIGLIST ! 1251: error ("%s terminated with signal %d %s", ! 1252: prog, ! 1253: sig, ! 1254: (status & 0200) ? ", core dumped" : ""); ! 1255: #else ! 1256: error ("%s terminated with signal %d [%s]%s", ! 1257: prog, ! 1258: sig, ! 1259: sys_siglist[sig], ! 1260: (status & 0200) ? ", core dumped" : ""); ! 1261: #endif ! 1262: ! 1263: my_exit (127); ! 1264: } ! 1265: ! 1266: ret = ((status & 0xFF00) >> 8); ! 1267: if (ret != -1 && ret != 0) ! 1268: { ! 1269: error ("%s returned %d exit status", prog, ret); ! 1270: my_exit (ret); ! 1271: } ! 1272: } ! 1273: } ! 1274: ! 1275: ! 1276: /* Fork and execute a program, and wait for the reply. */ ! 1277: ! 1278: static void ! 1279: fork_execute (prog, argv) ! 1280: char *prog; ! 1281: char **argv; ! 1282: { ! 1283: int pid; ! 1284: ! 1285: if (vflag || debug) ! 1286: { ! 1287: char **p_argv; ! 1288: char *str; ! 1289: ! 1290: if (argv[0]) ! 1291: fprintf (stderr, "%s", argv[0]); ! 1292: else ! 1293: fprintf (stderr, "[cannot find %s]", prog); ! 1294: ! 1295: for (p_argv = &argv[1]; (str = *p_argv) != (char *)0; p_argv++) ! 1296: fprintf (stderr, " %s", str); ! 1297: ! 1298: fprintf (stderr, "\n"); ! 1299: } ! 1300: ! 1301: fflush (stdout); ! 1302: fflush (stderr); ! 1303: ! 1304: /* If we can't find a program we need, complain error. Do this here ! 1305: since we might not end up needing something that we couldn't find. */ ! 1306: ! 1307: if (argv[0] == 0) ! 1308: fatal ("cannot find `%s'", prog); ! 1309: ! 1310: pid = vfork (); ! 1311: if (pid == -1) ! 1312: { ! 1313: #ifdef vfork ! 1314: fatal_perror ("fork"); ! 1315: #else ! 1316: fatal_perror ("vfork"); ! 1317: #endif ! 1318: } ! 1319: ! 1320: if (pid == 0) /* child context */ ! 1321: { ! 1322: execvp (argv[0], argv); ! 1323: fatal_perror ("executing %s", prog); ! 1324: } ! 1325: ! 1326: do_wait (prog); ! 1327: } ! 1328: ! 1329: ! 1330: /* Unlink a file unless we are debugging. */ ! 1331: ! 1332: static void ! 1333: maybe_unlink (file) ! 1334: char *file; ! 1335: { ! 1336: if (!debug) ! 1337: unlink (file); ! 1338: else ! 1339: fprintf (stderr, "[Leaving %s]\n", file); ! 1340: } ! 1341: ! 1342: ! 1343: /* Add a name to a linked list. */ ! 1344: ! 1345: static void ! 1346: add_to_list (head_ptr, name) ! 1347: struct head *head_ptr; ! 1348: char *name; ! 1349: { ! 1350: struct id *newid = (struct id *) xcalloc (sizeof (*newid) + strlen (name), 1); ! 1351: static long sequence_number = 0; ! 1352: newid->sequence = ++sequence_number; ! 1353: strcpy (newid->name, name); ! 1354: ! 1355: if (head_ptr->first) ! 1356: head_ptr->last->next = newid; ! 1357: else ! 1358: head_ptr->first = newid; ! 1359: ! 1360: head_ptr->last = newid; ! 1361: head_ptr->number++; ! 1362: } ! 1363: ! 1364: /* Write: `prefix', the names on list LIST, `suffix'. */ ! 1365: ! 1366: static void ! 1367: write_list (stream, prefix, list) ! 1368: FILE *stream; ! 1369: char *prefix; ! 1370: struct id *list; ! 1371: { ! 1372: while (list) ! 1373: { ! 1374: fprintf (stream, "%sx%d,\n", prefix, list->sequence); ! 1375: list = list->next; ! 1376: } ! 1377: } ! 1378: ! 1379: static void ! 1380: write_list_with_asm (stream, prefix, list) ! 1381: FILE *stream; ! 1382: char *prefix; ! 1383: struct id *list; ! 1384: { ! 1385: while (list) ! 1386: { ! 1387: fprintf (stream, "%sx%d __asm__ (\"%s\");\n", ! 1388: prefix, list->sequence, list->name); ! 1389: list = list->next; ! 1390: } ! 1391: } ! 1392: ! 1393: /* Write the constructor/destructor tables. */ ! 1394: ! 1395: static void ! 1396: write_c_file (stream, name) ! 1397: FILE *stream; ! 1398: char *name; ! 1399: { ! 1400: /* Write the tables as C code */ ! 1401: ! 1402: fprintf (stream, "typedef void entry_pt();\n\n"); ! 1403: ! 1404: write_list_with_asm (stream, "extern entry_pt ", constructors.first); ! 1405: ! 1406: fprintf (stream, "\nentry_pt * __CTOR_LIST__[] = {\n"); ! 1407: fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number); ! 1408: write_list (stream, "\t", constructors.first); ! 1409: fprintf (stream, "\t0\n};\n\n"); ! 1410: ! 1411: write_list_with_asm (stream, "extern entry_pt ", destructors.first); ! 1412: ! 1413: fprintf (stream, "\nentry_pt * __DTOR_LIST__[] = {\n"); ! 1414: fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number); ! 1415: write_list (stream, "\t", destructors.first); ! 1416: fprintf (stream, "\t0\n};\n\n"); ! 1417: ! 1418: fprintf (stream, "extern entry_pt %s;\n", NAME__MAIN); ! 1419: fprintf (stream, "entry_pt *__main_reference = %s;\n\n", NAME__MAIN); ! 1420: } ! 1421: ! 1422: ! 1423: #ifdef OBJECT_FORMAT_NONE ! 1424: ! 1425: /* Generic version to scan the name list of the loaded program for ! 1426: the symbols g++ uses for static constructors and destructors. ! 1427: ! 1428: The constructor table begins at __CTOR_LIST__ and contains a count ! 1429: of the number of pointers (or -1 if the constructors are built in a ! 1430: separate section by the linker), followed by the pointers to the ! 1431: constructor functions, terminated with a null pointer. The ! 1432: destructor table has the same format, and begins at __DTOR_LIST__. */ ! 1433: ! 1434: static void ! 1435: scan_prog_file (prog_name, which_pass) ! 1436: char *prog_name; ! 1437: enum pass which_pass; ! 1438: { ! 1439: void (*int_handler) (); ! 1440: void (*quit_handler) (); ! 1441: char *nm_argv[4]; ! 1442: int pid; ! 1443: int argc = 0; ! 1444: int pipe_fd[2]; ! 1445: char *p, buf[1024]; ! 1446: FILE *inf; ! 1447: ! 1448: if (which_pass != PASS_FIRST) ! 1449: return; ! 1450: ! 1451: /* If we don't have an `nm', complain. */ ! 1452: if (nm_file_name == 0) ! 1453: fatal ("cannot find `nm'"); ! 1454: ! 1455: nm_argv[argc++] = "nm"; ! 1456: if (NM_FLAGS[0] != '\0') ! 1457: nm_argv[argc++] = NM_FLAGS; ! 1458: ! 1459: nm_argv[argc++] = prog_name; ! 1460: nm_argv[argc++] = (char *)0; ! 1461: ! 1462: if (pipe (pipe_fd) < 0) ! 1463: fatal_perror ("pipe"); ! 1464: ! 1465: inf = fdopen (pipe_fd[0], "r"); ! 1466: if (inf == (FILE *)0) ! 1467: fatal_perror ("fdopen"); ! 1468: ! 1469: /* Trace if needed. */ ! 1470: if (vflag) ! 1471: { ! 1472: char **p_argv; ! 1473: char *str; ! 1474: ! 1475: fprintf (stderr, "%s", nm_file_name); ! 1476: for (p_argv = &nm_argv[1]; (str = *p_argv) != (char *)0; p_argv++) ! 1477: fprintf (stderr, " %s", str); ! 1478: ! 1479: fprintf (stderr, "\n"); ! 1480: } ! 1481: ! 1482: fflush (stdout); ! 1483: fflush (stderr); ! 1484: ! 1485: /* Spawn child nm on pipe */ ! 1486: pid = vfork (); ! 1487: if (pid == -1) ! 1488: { ! 1489: #ifdef vfork ! 1490: fatal_perror ("fork"); ! 1491: #else ! 1492: fatal_perror ("vfork"); ! 1493: #endif ! 1494: } ! 1495: ! 1496: if (pid == 0) /* child context */ ! 1497: { ! 1498: /* setup stdout */ ! 1499: if (dup2 (pipe_fd[1], 1) < 0) ! 1500: fatal_perror ("dup2 (%d, 1)", pipe_fd[1]); ! 1501: ! 1502: if (close (pipe_fd[0]) < 0) ! 1503: fatal_perror ("close (%d)", pipe_fd[0]); ! 1504: ! 1505: if (close (pipe_fd[1]) < 0) ! 1506: fatal_perror ("close (%d)", pipe_fd[1]); ! 1507: ! 1508: execv (nm_file_name, nm_argv); ! 1509: fatal_perror ("executing %s", nm_file_name); ! 1510: } ! 1511: ! 1512: /* Parent context from here on. */ ! 1513: int_handler = (void (*) ())signal (SIGINT, SIG_IGN); ! 1514: #ifdef SIGQUIT ! 1515: quit_handler = (void (*) ())signal (SIGQUIT, SIG_IGN); ! 1516: #endif ! 1517: ! 1518: if (close (pipe_fd[1]) < 0) ! 1519: fatal_perror ("close (%d)", pipe_fd[1]); ! 1520: ! 1521: if (debug) ! 1522: fprintf (stderr, "\nnm output with constructors/destructors.\n"); ! 1523: ! 1524: /* Read each line of nm output. */ ! 1525: while (fgets (buf, sizeof buf, inf) != (char *)0) ! 1526: { ! 1527: int ch, ch2; ! 1528: char *name, *end; ! 1529: ! 1530: /* If it contains a constructor or destructor name, add the name ! 1531: to the appropriate list. */ ! 1532: ! 1533: for (p = buf; (ch = *p) != '\0' && ch != '\n' && ch != '_'; p++) ! 1534: ; ! 1535: ! 1536: if (ch == '\0' || ch == '\n') ! 1537: continue; ! 1538: ! 1539: name = p; ! 1540: /* Find the end of the symbol name. ! 1541: Don't include `|', because Encore nm can tack that on the end. */ ! 1542: for (end = p; (ch2 = *end) != '\0' && !isspace (ch2) && ch2 != '|'; ! 1543: end++) ! 1544: continue; ! 1545: ! 1546: *end = '\0'; ! 1547: switch (is_ctor_dtor (name)) ! 1548: { ! 1549: case 1: ! 1550: add_to_list (&constructors, name); ! 1551: break; ! 1552: ! 1553: case 2: ! 1554: add_to_list (&destructors, name); ! 1555: break; ! 1556: ! 1557: default: /* not a constructor or destructor */ ! 1558: continue; ! 1559: } ! 1560: ! 1561: if (debug) ! 1562: fprintf (stderr, "\t%s\n", buf); ! 1563: } ! 1564: ! 1565: if (debug) ! 1566: fprintf (stderr, "\n"); ! 1567: ! 1568: if (fclose (inf) != 0) ! 1569: fatal_perror ("fclose of pipe"); ! 1570: ! 1571: do_wait (nm_file_name); ! 1572: ! 1573: signal (SIGINT, int_handler); ! 1574: #ifdef SIGQUIT ! 1575: signal (SIGQUIT, quit_handler); ! 1576: #endif ! 1577: } ! 1578: ! 1579: #endif /* OBJECT_FORMAT_NONE */ ! 1580: ! 1581: ! 1582: /* ! 1583: * COFF specific stuff. ! 1584: */ ! 1585: ! 1586: #ifdef OBJECT_FORMAT_COFF ! 1587: ! 1588: #if defined(EXTENDED_COFF) ! 1589: # define GCC_SYMBOLS(X) (SYMHEADER(X).isymMax + SYMHEADER(X).iextMax) ! 1590: # define GCC_SYMENT SYMR ! 1591: # define GCC_OK_SYMBOL(X) ((X).st == stProc && (X).sc == scText) ! 1592: # define GCC_SYMINC(X) (1) ! 1593: # define GCC_SYMZERO(X) (SYMHEADER(X).isymMax) ! 1594: # define GCC_CHECK_HDR(X) (PSYMTAB(X) != 0) ! 1595: #else ! 1596: # define GCC_SYMBOLS(X) (HEADER(ldptr).f_nsyms) ! 1597: # define GCC_SYMENT SYMENT ! 1598: # define GCC_OK_SYMBOL(X) \ ! 1599: (((X).n_sclass == C_EXT) && \ ! 1600: (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) || \ ! 1601: ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT))) ! 1602: # define GCC_SYMINC(X) ((X).n_numaux+1) ! 1603: # define GCC_SYMZERO(X) 0 ! 1604: # define GCC_CHECK_HDR(X) (1) ! 1605: #endif ! 1606: ! 1607: extern char *ldgetname (); ! 1608: ! 1609: /* COFF version to scan the name list of the loaded program for ! 1610: the symbols g++ uses for static constructors and destructors. ! 1611: ! 1612: The constructor table begins at __CTOR_LIST__ and contains a count ! 1613: of the number of pointers (or -1 if the constructors are built in a ! 1614: separate section by the linker), followed by the pointers to the ! 1615: constructor functions, terminated with a null pointer. The ! 1616: destructor table has the same format, and begins at __DTOR_LIST__. */ ! 1617: ! 1618: static void ! 1619: scan_prog_file (prog_name, which_pass) ! 1620: char *prog_name; ! 1621: enum pass which_pass; ! 1622: { ! 1623: LDFILE *ldptr = NULL; ! 1624: int sym_index, sym_count; ! 1625: ! 1626: if (which_pass != PASS_FIRST) ! 1627: return; ! 1628: ! 1629: if ((ldptr = ldopen (prog_name, ldptr)) == NULL) ! 1630: fatal ("%s: can't open as COFF file", prog_name); ! 1631: ! 1632: if (!MY_ISCOFF (HEADER (ldptr).f_magic)) ! 1633: fatal ("%s: not a COFF file", prog_name); ! 1634: ! 1635: if (GCC_CHECK_HDR (ldptr)) ! 1636: { ! 1637: sym_count = GCC_SYMBOLS (ldptr); ! 1638: sym_index = GCC_SYMZERO (ldptr); ! 1639: while (sym_index < sym_count) ! 1640: { ! 1641: GCC_SYMENT symbol; ! 1642: ! 1643: if (ldtbread (ldptr, sym_index, &symbol) <= 0) ! 1644: break; ! 1645: sym_index += GCC_SYMINC (symbol); ! 1646: ! 1647: if (GCC_OK_SYMBOL (symbol)) ! 1648: { ! 1649: char *name; ! 1650: ! 1651: if ((name = ldgetname (ldptr, &symbol)) == NULL) ! 1652: continue; /* should never happen */ ! 1653: ! 1654: #ifdef _AIX ! 1655: /* All AIX function names begin with a dot. */ ! 1656: if (*name++ != '.') ! 1657: continue; ! 1658: #endif ! 1659: ! 1660: switch (is_ctor_dtor (name)) ! 1661: { ! 1662: case 1: ! 1663: add_to_list (&constructors, name); ! 1664: break; ! 1665: ! 1666: case 2: ! 1667: add_to_list (&destructors, name); ! 1668: break; ! 1669: ! 1670: default: /* not a constructor or destructor */ ! 1671: continue; ! 1672: } ! 1673: ! 1674: #if !defined(EXTENDED_COFF) ! 1675: if (debug) ! 1676: fprintf (stderr, "\tsec=%d class=%d type=%s%o %s\n", ! 1677: symbol.n_scnum, symbol.n_sclass, ! 1678: (symbol.n_type ? "0" : ""), symbol.n_type, ! 1679: name); ! 1680: #else ! 1681: if (debug) ! 1682: fprintf (stderr, "\tiss = %5d, value = %5d, index = %5d, name = %s\n", ! 1683: symbol.iss, symbol.value, symbol.index, name); ! 1684: #endif ! 1685: } ! 1686: } ! 1687: } ! 1688: ! 1689: (void) ldclose(ldptr); ! 1690: } ! 1691: ! 1692: #endif /* OBJECT_FORMAT_COFF */ ! 1693: ! 1694: ! 1695: /* ! 1696: * OSF/rose specific stuff. ! 1697: */ ! 1698: ! 1699: #ifdef OBJECT_FORMAT_ROSE ! 1700: ! 1701: /* Union of the various load commands */ ! 1702: ! 1703: typedef union load_union ! 1704: { ! 1705: ldc_header_t hdr; /* common header */ ! 1706: load_cmd_map_command_t map; /* map indexing other load cmds */ ! 1707: interpreter_command_t iprtr; /* interpreter pathname */ ! 1708: strings_command_t str; /* load commands strings section */ ! 1709: region_command_t region; /* region load command */ ! 1710: reloc_command_t reloc; /* relocation section */ ! 1711: package_command_t pkg; /* package load command */ ! 1712: symbols_command_t sym; /* symbol sections */ ! 1713: entry_command_t ent; /* program start section */ ! 1714: gen_info_command_t info; /* object information */ ! 1715: func_table_command_t func; /* function constructors/destructors */ ! 1716: } load_union_t; ! 1717: ! 1718: /* Structure to point to load command and data section in memory. */ ! 1719: ! 1720: typedef struct load_all ! 1721: { ! 1722: load_union_t *load; /* load command */ ! 1723: char *section; /* pointer to section */ ! 1724: } load_all_t; ! 1725: ! 1726: /* Structure to contain information about a file mapped into memory. */ ! 1727: ! 1728: struct file_info ! 1729: { ! 1730: char *start; /* start of map */ ! 1731: char *name; /* filename */ ! 1732: long size; /* size of the file */ ! 1733: long rounded_size; /* size rounded to page boundary */ ! 1734: int fd; /* file descriptor */ ! 1735: int rw; /* != 0 if opened read/write */ ! 1736: int use_mmap; /* != 0 if mmap'ed */ ! 1737: }; ! 1738: ! 1739: extern int decode_mach_o_hdr (); ! 1740: extern int encode_mach_o_hdr (); ! 1741: ! 1742: static void add_func_table PROTO((mo_header_t *, load_all_t *, ! 1743: symbol_info_t *, int)); ! 1744: static void print_header PROTO((mo_header_t *)); ! 1745: static void print_load_command PROTO((load_union_t*, size_t, int)); ! 1746: static void bad_header PROTO((int)); ! 1747: static struct file_info *read_file PROTO((char *, int, int)); ! 1748: static void end_file PROTO((struct file_info *)); ! 1749: ! 1750: /* OSF/rose specific version to scan the name list of the loaded ! 1751: program for the symbols g++ uses for static constructors and ! 1752: destructors. ! 1753: ! 1754: The constructor table begins at __CTOR_LIST__ and contains a count ! 1755: of the number of pointers (or -1 if the constructors are built in a ! 1756: separate section by the linker), followed by the pointers to the ! 1757: constructor functions, terminated with a null pointer. The ! 1758: destructor table has the same format, and begins at __DTOR_LIST__. */ ! 1759: ! 1760: static void ! 1761: scan_prog_file (prog_name, which_pass) ! 1762: char *prog_name; ! 1763: enum pass which_pass; ! 1764: { ! 1765: char *obj; ! 1766: mo_header_t hdr; ! 1767: load_all_t *load_array; ! 1768: load_all_t *load_end; ! 1769: load_all_t *load_cmd; ! 1770: int symbol_load_cmds; ! 1771: off_t offset; ! 1772: int i; ! 1773: int num_syms; ! 1774: int status; ! 1775: char *str_sect; ! 1776: struct file_info *obj_file; ! 1777: int prog_fd; ! 1778: mo_lcid_t cmd_strings = -1; ! 1779: symbol_info_t *main_sym = 0; ! 1780: int rw = (which_pass != PASS_FIRST); ! 1781: ! 1782: prog_fd = open (prog_name, (rw) ? O_RDWR : O_RDONLY); ! 1783: if (prog_fd < 0) ! 1784: fatal_perror ("can't read %s", prog_name); ! 1785: ! 1786: obj_file = read_file (prog_name, prog_fd, rw); ! 1787: obj = obj_file->start; ! 1788: ! 1789: status = decode_mach_o_hdr (obj, MO_SIZEOF_RAW_HDR, MOH_HEADER_VERSION, &hdr); ! 1790: if (status != MO_HDR_CONV_SUCCESS) ! 1791: bad_header (status); ! 1792: ! 1793: ! 1794: /* Do some basic sanity checks. Note we explicitly use the big endian magic number, ! 1795: since the hardware will automatically swap bytes for us on loading little endian ! 1796: integers. */ ! 1797: ! 1798: #ifndef CROSS_COMPILE ! 1799: if (hdr.moh_magic != MOH_MAGIC_MSB ! 1800: || hdr.moh_header_version != MOH_HEADER_VERSION ! 1801: || hdr.moh_byte_order != OUR_BYTE_ORDER ! 1802: || hdr.moh_data_rep_id != OUR_DATA_REP_ID ! 1803: || hdr.moh_cpu_type != OUR_CPU_TYPE ! 1804: || hdr.moh_cpu_subtype != OUR_CPU_SUBTYPE ! 1805: || hdr.moh_vendor_type != OUR_VENDOR_TYPE) ! 1806: { ! 1807: fatal ("incompatibilities between object file & expected values"); ! 1808: } ! 1809: #endif ! 1810: ! 1811: if (debug) ! 1812: print_header (&hdr); ! 1813: ! 1814: offset = hdr.moh_first_cmd_off; ! 1815: load_end = load_array ! 1816: = (load_all_t *) xcalloc (sizeof (load_all_t), hdr.moh_n_load_cmds + 2); ! 1817: ! 1818: /* Build array of load commands, calculating the offsets */ ! 1819: for (i = 0; i < hdr.moh_n_load_cmds; i++) ! 1820: { ! 1821: load_union_t *load_hdr; /* load command header */ ! 1822: ! 1823: load_cmd = load_end++; ! 1824: load_hdr = (load_union_t *) (obj + offset); ! 1825: ! 1826: /* If modifying the program file, copy the header. */ ! 1827: if (rw) ! 1828: { ! 1829: load_union_t *ptr = (load_union_t *) xmalloc (load_hdr->hdr.ldci_cmd_size); ! 1830: bcopy ((generic *)load_hdr, (generic *)ptr, load_hdr->hdr.ldci_cmd_size); ! 1831: load_hdr = ptr; ! 1832: ! 1833: /* null out old command map, because we will rewrite at the end. */ ! 1834: if (ptr->hdr.ldci_cmd_type == LDC_CMD_MAP) ! 1835: { ! 1836: cmd_strings = ptr->map.lcm_ld_cmd_strings; ! 1837: ptr->hdr.ldci_cmd_type = LDC_UNDEFINED; ! 1838: } ! 1839: } ! 1840: ! 1841: load_cmd->load = load_hdr; ! 1842: if (load_hdr->hdr.ldci_section_off > 0) ! 1843: load_cmd->section = obj + load_hdr->hdr.ldci_section_off; ! 1844: ! 1845: if (debug) ! 1846: print_load_command (load_hdr, offset, i); ! 1847: ! 1848: offset += load_hdr->hdr.ldci_cmd_size; ! 1849: } ! 1850: ! 1851: /* If the last command is the load command map and is not undefined, ! 1852: decrement the count of load commands. */ ! 1853: if (rw && load_end[-1].load->hdr.ldci_cmd_type == LDC_UNDEFINED) ! 1854: { ! 1855: load_end--; ! 1856: hdr.moh_n_load_cmds--; ! 1857: } ! 1858: ! 1859: /* Go through and process each symbol table section. */ ! 1860: symbol_load_cmds = 0; ! 1861: for (load_cmd = load_array; load_cmd < load_end; load_cmd++) ! 1862: { ! 1863: load_union_t *load_hdr = load_cmd->load; ! 1864: ! 1865: if (load_hdr->hdr.ldci_cmd_type == LDC_SYMBOLS) ! 1866: { ! 1867: symbol_load_cmds++; ! 1868: ! 1869: if (debug) ! 1870: { ! 1871: char *kind = "unknown"; ! 1872: ! 1873: switch (load_hdr->sym.symc_kind) ! 1874: { ! 1875: case SYMC_IMPORTS: kind = "imports"; break; ! 1876: case SYMC_DEFINED_SYMBOLS: kind = "defined"; break; ! 1877: case SYMC_STABS: kind = "stabs"; break; ! 1878: } ! 1879: ! 1880: fprintf (stderr, "\nProcessing symbol table #%d, offset = 0x%.8lx, kind = %s\n", ! 1881: symbol_load_cmds, load_hdr->hdr.ldci_section_off, kind); ! 1882: } ! 1883: ! 1884: if (load_hdr->sym.symc_kind != SYMC_DEFINED_SYMBOLS) ! 1885: continue; ! 1886: ! 1887: str_sect = load_array[load_hdr->sym.symc_strings_section].section; ! 1888: if (str_sect == (char *)0) ! 1889: fatal ("string section missing"); ! 1890: ! 1891: if (load_cmd->section == (char *)0) ! 1892: fatal ("section pointer missing"); ! 1893: ! 1894: num_syms = load_hdr->sym.symc_nentries; ! 1895: for (i = 0; i < num_syms; i++) ! 1896: { ! 1897: symbol_info_t *sym = ((symbol_info_t *) load_cmd->section) + i; ! 1898: char *name = sym->si_name.symbol_name + str_sect; ! 1899: ! 1900: if (name[0] != '_') ! 1901: continue; ! 1902: ! 1903: if (rw) ! 1904: { ! 1905: char *n = name + strlen (name) - strlen (NAME__MAIN); ! 1906: ! 1907: if ((n - name) < 0 || strcmp (n, NAME__MAIN)) ! 1908: continue; ! 1909: while (n != name) ! 1910: if (*--n != '_') ! 1911: continue; ! 1912: ! 1913: main_sym = sym; ! 1914: } ! 1915: else ! 1916: { ! 1917: switch (is_ctor_dtor (name)) ! 1918: { ! 1919: case 1: ! 1920: add_to_list (&constructors, name); ! 1921: break; ! 1922: ! 1923: case 2: ! 1924: add_to_list (&destructors, name); ! 1925: break; ! 1926: ! 1927: default: /* not a constructor or destructor */ ! 1928: continue; ! 1929: } ! 1930: } ! 1931: ! 1932: if (debug) ! 1933: fprintf (stderr, "\ttype = 0x%.4x, sc = 0x%.2x, flags = 0x%.8x, name = %.30s\n", ! 1934: sym->si_type, sym->si_sc_type, sym->si_flags, name); ! 1935: } ! 1936: } ! 1937: } ! 1938: ! 1939: if (symbol_load_cmds == 0) ! 1940: fatal ("no symbol table found"); ! 1941: ! 1942: /* Update the program file now, rewrite header and load commands. At present, ! 1943: we assume that there is enough space after the last load command to insert ! 1944: one more. Since the first section written out is page aligned, and the ! 1945: number of load commands is small, this is ok for the present. */ ! 1946: ! 1947: if (rw) ! 1948: { ! 1949: load_union_t *load_map; ! 1950: size_t size; ! 1951: ! 1952: if (cmd_strings == -1) ! 1953: fatal ("no cmd_strings found"); ! 1954: ! 1955: /* Add __main to initializer list. ! 1956: If we are building a program instead of a shared library, don't ! 1957: do anything, since in the current version, you cannot do mallocs ! 1958: and such in the constructors. */ ! 1959: ! 1960: if (main_sym != (symbol_info_t *)0 ! 1961: && ((hdr.moh_flags & MOH_EXECABLE_F) == 0)) ! 1962: add_func_table (&hdr, load_array, main_sym, FNTC_INITIALIZATION); ! 1963: ! 1964: if (debug) ! 1965: fprintf (stderr, "\nUpdating header and load commands.\n\n"); ! 1966: ! 1967: hdr.moh_n_load_cmds++; ! 1968: size = sizeof (load_cmd_map_command_t) + (sizeof (mo_offset_t) * (hdr.moh_n_load_cmds - 1)); ! 1969: ! 1970: /* Create new load command map. */ ! 1971: if (debug) ! 1972: fprintf (stderr, "load command map, %d cmds, new size %ld.\n", ! 1973: (int)hdr.moh_n_load_cmds, (long)size); ! 1974: ! 1975: load_map = (load_union_t *) xcalloc (1, size); ! 1976: load_map->map.ldc_header.ldci_cmd_type = LDC_CMD_MAP; ! 1977: load_map->map.ldc_header.ldci_cmd_size = size; ! 1978: load_map->map.lcm_ld_cmd_strings = cmd_strings; ! 1979: load_map->map.lcm_nentries = hdr.moh_n_load_cmds; ! 1980: load_array[hdr.moh_n_load_cmds-1].load = load_map; ! 1981: ! 1982: offset = hdr.moh_first_cmd_off; ! 1983: for (i = 0; i < hdr.moh_n_load_cmds; i++) ! 1984: { ! 1985: load_map->map.lcm_map[i] = offset; ! 1986: if (load_array[i].load->hdr.ldci_cmd_type == LDC_CMD_MAP) ! 1987: hdr.moh_load_map_cmd_off = offset; ! 1988: ! 1989: offset += load_array[i].load->hdr.ldci_cmd_size; ! 1990: } ! 1991: ! 1992: hdr.moh_sizeofcmds = offset - MO_SIZEOF_RAW_HDR; ! 1993: ! 1994: if (debug) ! 1995: print_header (&hdr); ! 1996: ! 1997: /* Write header */ ! 1998: status = encode_mach_o_hdr (&hdr, obj, MO_SIZEOF_RAW_HDR); ! 1999: if (status != MO_HDR_CONV_SUCCESS) ! 2000: bad_header (status); ! 2001: ! 2002: if (debug) ! 2003: fprintf (stderr, "writing load commands.\n\n"); ! 2004: ! 2005: /* Write load commands */ ! 2006: offset = hdr.moh_first_cmd_off; ! 2007: for (i = 0; i < hdr.moh_n_load_cmds; i++) ! 2008: { ! 2009: load_union_t *load_hdr = load_array[i].load; ! 2010: size_t size = load_hdr->hdr.ldci_cmd_size; ! 2011: ! 2012: if (debug) ! 2013: print_load_command (load_hdr, offset, i); ! 2014: ! 2015: bcopy ((generic *)load_hdr, (generic *)(obj + offset), size); ! 2016: offset += size; ! 2017: } ! 2018: } ! 2019: ! 2020: end_file (obj_file); ! 2021: ! 2022: if (close (prog_fd)) ! 2023: fatal_perror ("closing %s", prog_name); ! 2024: ! 2025: if (debug) ! 2026: fprintf (stderr, "\n"); ! 2027: } ! 2028: ! 2029: ! 2030: /* Add a function table to the load commands to call a function ! 2031: on initiation or termination of the process. */ ! 2032: ! 2033: static void ! 2034: add_func_table (hdr_p, load_array, sym, type) ! 2035: mo_header_t *hdr_p; /* pointer to global header */ ! 2036: load_all_t *load_array; /* array of ptrs to load cmds */ ! 2037: symbol_info_t *sym; /* pointer to symbol entry */ ! 2038: int type; /* fntc_type value */ ! 2039: { ! 2040: /* Add a new load command. */ ! 2041: int num_cmds = ++hdr_p->moh_n_load_cmds; ! 2042: int load_index = num_cmds - 1; ! 2043: size_t size = sizeof (func_table_command_t) + sizeof (mo_addr_t); ! 2044: load_union_t *ptr = xcalloc (1, size); ! 2045: load_all_t *load_cmd; ! 2046: int i; ! 2047: ! 2048: /* Set the unresolved address bit in the header to force the loader to be ! 2049: used, since kernel exec does not call the initialization functions. */ ! 2050: hdr_p->moh_flags |= MOH_UNRESOLVED_F; ! 2051: ! 2052: load_cmd = &load_array[load_index]; ! 2053: load_cmd->load = ptr; ! 2054: load_cmd->section = (char *)0; ! 2055: ! 2056: /* Fill in func table load command. */ ! 2057: ptr->func.ldc_header.ldci_cmd_type = LDC_FUNC_TABLE; ! 2058: ptr->func.ldc_header.ldci_cmd_size = size; ! 2059: ptr->func.ldc_header.ldci_section_off = 0; ! 2060: ptr->func.ldc_header.ldci_section_len = 0; ! 2061: ptr->func.fntc_type = type; ! 2062: ptr->func.fntc_nentries = 1; ! 2063: ! 2064: /* copy address, turn it from abs. address to (region,offset) if necessary. */ ! 2065: /* Is the symbol already expressed as (region, offset)? */ ! 2066: if ((sym->si_flags & SI_ABSOLUTE_VALUE_F) == 0) ! 2067: { ! 2068: ptr->func.fntc_entry_loc[i].adr_lcid = sym->si_value.def_val.adr_lcid; ! 2069: ptr->func.fntc_entry_loc[i].adr_sctoff = sym->si_value.def_val.adr_sctoff; ! 2070: } ! 2071: ! 2072: /* If not, figure out which region it's in. */ ! 2073: else ! 2074: { ! 2075: mo_vm_addr_t addr = sym->si_value.abs_val; ! 2076: int found = 0; ! 2077: ! 2078: for (i = 0; i < load_index; i++) ! 2079: { ! 2080: if (load_array[i].load->hdr.ldci_cmd_type == LDC_REGION) ! 2081: { ! 2082: region_command_t *region_ptr = &load_array[i].load->region; ! 2083: ! 2084: if ((region_ptr->regc_flags & REG_ABS_ADDR_F) != 0 ! 2085: && addr >= region_ptr->regc_addr.vm_addr ! 2086: && addr <= region_ptr->regc_addr.vm_addr + region_ptr->regc_vm_size) ! 2087: { ! 2088: ptr->func.fntc_entry_loc[0].adr_lcid = i; ! 2089: ptr->func.fntc_entry_loc[0].adr_sctoff = addr - region_ptr->regc_addr.vm_addr; ! 2090: found++; ! 2091: break; ! 2092: } ! 2093: } ! 2094: } ! 2095: ! 2096: if (!found) ! 2097: fatal ("could not convert 0x%l.8x into a region", addr); ! 2098: } ! 2099: ! 2100: if (debug) ! 2101: fprintf (stderr, ! 2102: "%s function, region %d, offset = %ld (0x%.8lx)\n", ! 2103: (type == FNTC_INITIALIZATION) ? "init" : "term", ! 2104: (int)ptr->func.fntc_entry_loc[i].adr_lcid, ! 2105: (long)ptr->func.fntc_entry_loc[i].adr_sctoff, ! 2106: (long)ptr->func.fntc_entry_loc[i].adr_sctoff); ! 2107: ! 2108: } ! 2109: ! 2110: ! 2111: /* Print the global header for an OSF/rose object. */ ! 2112: ! 2113: static void ! 2114: print_header (hdr_ptr) ! 2115: mo_header_t *hdr_ptr; ! 2116: { ! 2117: fprintf (stderr, "\nglobal header:\n"); ! 2118: fprintf (stderr, "\tmoh_magic = 0x%.8lx\n", hdr_ptr->moh_magic); ! 2119: fprintf (stderr, "\tmoh_major_version = %d\n", (int)hdr_ptr->moh_major_version); ! 2120: fprintf (stderr, "\tmoh_minor_version = %d\n", (int)hdr_ptr->moh_minor_version); ! 2121: fprintf (stderr, "\tmoh_header_version = %d\n", (int)hdr_ptr->moh_header_version); ! 2122: fprintf (stderr, "\tmoh_max_page_size = %d\n", (int)hdr_ptr->moh_max_page_size); ! 2123: fprintf (stderr, "\tmoh_byte_order = %d\n", (int)hdr_ptr->moh_byte_order); ! 2124: fprintf (stderr, "\tmoh_data_rep_id = %d\n", (int)hdr_ptr->moh_data_rep_id); ! 2125: fprintf (stderr, "\tmoh_cpu_type = %d\n", (int)hdr_ptr->moh_cpu_type); ! 2126: fprintf (stderr, "\tmoh_cpu_subtype = %d\n", (int)hdr_ptr->moh_cpu_subtype); ! 2127: fprintf (stderr, "\tmoh_vendor_type = %d\n", (int)hdr_ptr->moh_vendor_type); ! 2128: fprintf (stderr, "\tmoh_load_map_cmd_off = %d\n", (int)hdr_ptr->moh_load_map_cmd_off); ! 2129: fprintf (stderr, "\tmoh_first_cmd_off = %d\n", (int)hdr_ptr->moh_first_cmd_off); ! 2130: fprintf (stderr, "\tmoh_sizeofcmds = %d\n", (int)hdr_ptr->moh_sizeofcmds); ! 2131: fprintf (stderr, "\tmon_n_load_cmds = %d\n", (int)hdr_ptr->moh_n_load_cmds); ! 2132: fprintf (stderr, "\tmoh_flags = 0x%.8lx", (long)hdr_ptr->moh_flags); ! 2133: ! 2134: if (hdr_ptr->moh_flags & MOH_RELOCATABLE_F) ! 2135: fprintf (stderr, ", relocatable"); ! 2136: ! 2137: if (hdr_ptr->moh_flags & MOH_LINKABLE_F) ! 2138: fprintf (stderr, ", linkable"); ! 2139: ! 2140: if (hdr_ptr->moh_flags & MOH_EXECABLE_F) ! 2141: fprintf (stderr, ", execable"); ! 2142: ! 2143: if (hdr_ptr->moh_flags & MOH_EXECUTABLE_F) ! 2144: fprintf (stderr, ", executable"); ! 2145: ! 2146: if (hdr_ptr->moh_flags & MOH_UNRESOLVED_F) ! 2147: fprintf (stderr, ", unresolved"); ! 2148: ! 2149: fprintf (stderr, "\n\n"); ! 2150: return; ! 2151: } ! 2152: ! 2153: ! 2154: /* Print a short summary of a load command. */ ! 2155: ! 2156: static void ! 2157: print_load_command (load_hdr, offset, number) ! 2158: load_union_t *load_hdr; ! 2159: size_t offset; ! 2160: int number; ! 2161: { ! 2162: mo_long_t type = load_hdr->hdr.ldci_cmd_type; ! 2163: char *type_str = (char *)0; ! 2164: ! 2165: switch (type) ! 2166: { ! 2167: case LDC_UNDEFINED: type_str = "UNDEFINED"; break; ! 2168: case LDC_CMD_MAP: type_str = "CMD_MAP"; break; ! 2169: case LDC_INTERPRETER: type_str = "INTERPRETER"; break; ! 2170: case LDC_STRINGS: type_str = "STRINGS"; break; ! 2171: case LDC_REGION: type_str = "REGION"; break; ! 2172: case LDC_RELOC: type_str = "RELOC"; break; ! 2173: case LDC_PACKAGE: type_str = "PACKAGE"; break; ! 2174: case LDC_SYMBOLS: type_str = "SYMBOLS"; break; ! 2175: case LDC_ENTRY: type_str = "ENTRY"; break; ! 2176: case LDC_FUNC_TABLE: type_str = "FUNC_TABLE"; break; ! 2177: case LDC_GEN_INFO: type_str = "GEN_INFO"; break; ! 2178: } ! 2179: ! 2180: fprintf (stderr, ! 2181: "cmd %2d, sz: 0x%.2lx, coff: 0x%.3lx, doff: 0x%.6lx, dlen: 0x%.6lx", ! 2182: number, ! 2183: (long) load_hdr->hdr.ldci_cmd_size, ! 2184: (long) offset, ! 2185: (long) load_hdr->hdr.ldci_section_off, ! 2186: (long) load_hdr->hdr.ldci_section_len); ! 2187: ! 2188: if (type_str == (char *)0) ! 2189: fprintf (stderr, ", ty: unknown (%ld)\n", (long) type); ! 2190: ! 2191: else if (type != LDC_REGION) ! 2192: fprintf (stderr, ", ty: %s\n", type_str); ! 2193: ! 2194: else ! 2195: { ! 2196: char *region = ""; ! 2197: switch (load_hdr->region.regc_usage_type) ! 2198: { ! 2199: case REG_TEXT_T: region = ", .text"; break; ! 2200: case REG_DATA_T: region = ", .data"; break; ! 2201: case REG_BSS_T: region = ", .bss"; break; ! 2202: case REG_GLUE_T: region = ", .glue"; break; ! 2203: #if defined (REG_RDATA_T) && defined (REG_SDATA_T) && defined (REG_SBSS_T) /*mips*/ ! 2204: case REG_RDATA_T: region = ", .rdata"; break; ! 2205: case REG_SDATA_T: region = ", .sdata"; break; ! 2206: case REG_SBSS_T: region = ", .sbss"; break; ! 2207: #endif ! 2208: } ! 2209: ! 2210: fprintf (stderr, ", ty: %s, vaddr: 0x%.8lx, vlen: 0x%.6lx%s\n", ! 2211: type_str, ! 2212: (long) load_hdr->region.regc_vm_addr, ! 2213: (long) load_hdr->region.regc_vm_size, ! 2214: region); ! 2215: } ! 2216: ! 2217: return; ! 2218: } ! 2219: ! 2220: ! 2221: /* Fatal error when {en,de}code_mach_o_header fails. */ ! 2222: ! 2223: static void ! 2224: bad_header (status) ! 2225: int status; ! 2226: { ! 2227: char *msg = (char *)0; ! 2228: ! 2229: switch (status) ! 2230: { ! 2231: case MO_ERROR_BAD_MAGIC: msg = "bad magic number"; break; ! 2232: case MO_ERROR_BAD_HDR_VERS: msg = "bad header version"; break; ! 2233: case MO_ERROR_BAD_RAW_HDR_VERS: msg = "bad raw header version"; break; ! 2234: case MO_ERROR_BUF2SML: msg = "raw header buffer too small"; break; ! 2235: case MO_ERROR_OLD_RAW_HDR_FILE: msg = "old raw header file"; break; ! 2236: case MO_ERROR_UNSUPPORTED_VERS: msg = "unsupported version"; break; ! 2237: } ! 2238: ! 2239: if (msg == (char *)0) ! 2240: fatal ("unknown {de,en}code_mach_o_hdr return value %d", status); ! 2241: else ! 2242: fatal ("%s", msg); ! 2243: } ! 2244: ! 2245: ! 2246: /* Read a file into a memory buffer. */ ! 2247: ! 2248: static struct file_info * ! 2249: read_file (name, fd, rw) ! 2250: char *name; /* filename */ ! 2251: int fd; /* file descriptor */ ! 2252: int rw; /* read/write */ ! 2253: { ! 2254: struct stat stat_pkt; ! 2255: struct file_info *p = (struct file_info *) xcalloc (sizeof (struct file_info), 1); ! 2256: #ifdef USE_MMAP ! 2257: static int page_size; ! 2258: #endif ! 2259: ! 2260: if (fstat (fd, &stat_pkt) < 0) ! 2261: fatal_perror ("fstat %s", name); ! 2262: ! 2263: p->name = name; ! 2264: p->size = stat_pkt.st_size; ! 2265: p->rounded_size = stat_pkt.st_size; ! 2266: p->fd = fd; ! 2267: p->rw = rw; ! 2268: ! 2269: #ifdef USE_MMAP ! 2270: if (debug) ! 2271: fprintf (stderr, "mmap %s, %s\n", name, (rw) ? "read/write" : "read-only"); ! 2272: ! 2273: if (page_size == 0) ! 2274: page_size = sysconf (_SC_PAGE_SIZE); ! 2275: ! 2276: p->rounded_size = ((p->size + page_size - 1) / page_size) * page_size; ! 2277: p->start = mmap ((caddr_t)0, ! 2278: (rw) ? p->rounded_size : p->size, ! 2279: (rw) ? (PROT_READ | PROT_WRITE) : PROT_READ, ! 2280: MAP_FILE | MAP_VARIABLE | MAP_SHARED, ! 2281: fd, ! 2282: 0L); ! 2283: ! 2284: if (p->start != (char *)0 && p->start != (char *)-1) ! 2285: p->use_mmap = 1; ! 2286: ! 2287: else ! 2288: #endif /* USE_MMAP */ ! 2289: { ! 2290: long len; ! 2291: ! 2292: if (debug) ! 2293: fprintf (stderr, "read %s\n", name); ! 2294: ! 2295: p->use_mmap = 0; ! 2296: p->start = xmalloc (p->size); ! 2297: if (lseek (fd, 0L, SEEK_SET) < 0) ! 2298: fatal_perror ("lseek to 0 on %s", name); ! 2299: ! 2300: len = read (fd, p->start, p->size); ! 2301: if (len < 0) ! 2302: fatal_perror ("read %s", name); ! 2303: ! 2304: if (len != p->size) ! 2305: fatal ("read %ld bytes, expected %ld, from %s", len, p->size, name); ! 2306: } ! 2307: ! 2308: return p; ! 2309: } ! 2310: ! 2311: /* Do anything necessary to write a file back from memory. */ ! 2312: ! 2313: static void ! 2314: end_file (ptr) ! 2315: struct file_info *ptr; /* file information block */ ! 2316: { ! 2317: #ifdef USE_MMAP ! 2318: if (ptr->use_mmap) ! 2319: { ! 2320: if (ptr->rw) ! 2321: { ! 2322: if (debug) ! 2323: fprintf (stderr, "msync %s\n", ptr->name); ! 2324: ! 2325: if (msync (ptr->start, ptr->rounded_size, MS_ASYNC)) ! 2326: fatal_perror ("msync %s", ptr->name); ! 2327: } ! 2328: ! 2329: if (debug) ! 2330: fprintf (stderr, "munmap %s\n", ptr->name); ! 2331: ! 2332: if (munmap (ptr->start, ptr->size)) ! 2333: fatal_perror ("munmap %s", ptr->name); ! 2334: } ! 2335: else ! 2336: #endif /* USE_MMAP */ ! 2337: { ! 2338: if (ptr->rw) ! 2339: { ! 2340: long len; ! 2341: ! 2342: if (debug) ! 2343: fprintf (stderr, "write %s\n", ptr->name); ! 2344: ! 2345: if (lseek (ptr->fd, 0L, SEEK_SET) < 0) ! 2346: fatal_perror ("lseek to 0 on %s", ptr->name); ! 2347: ! 2348: len = write (ptr->fd, ptr->start, ptr->size); ! 2349: if (len < 0) ! 2350: fatal_perror ("read %s", ptr->name); ! 2351: ! 2352: if (len != ptr->size) ! 2353: fatal ("wrote %ld bytes, expected %ld, to %s", len, ptr->size, ptr->name); ! 2354: } ! 2355: ! 2356: free ((generic *)ptr->start); ! 2357: } ! 2358: ! 2359: free ((generic *)ptr); ! 2360: } ! 2361: ! 2362: #endif /* OBJECT_FORMAT_ROSE */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.