📄 collect2.c
字号:
} c_ptr = c_argv = (char **) xcalloc (sizeof (char *), num_c_args); if (argc < 2) fatal ("no arguments"); if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) signal (SIGQUIT, handler); if (signal (SIGINT, SIG_IGN) != SIG_IGN) signal (SIGINT, handler); if (signal (SIGALRM, SIG_IGN) != SIG_IGN) signal (SIGALRM, handler); if (signal (SIGHUP, SIG_IGN) != SIG_IGN) signal (SIGHUP, handler); if (signal (SIGSEGV, SIG_IGN) != SIG_IGN) signal (SIGSEGV, handler); if (signal (SIGBUS, SIG_IGN) != SIG_IGN) signal (SIGBUS, handler); /* Try to discover a valid linker/assembler/nm/strip to use. */ len = strlen (argv[0]); prefix = (char *)0; if (len >= sizeof ("ld")-1) { p = argv[0] + len - sizeof ("ld") + 1; if (strcmp (p, "ld") == 0) { prefix = argv[0]; *p = '\0'; } } if (prefix == (char *)0) { p = rindex (argv[0], '/'); if (p != (char *)0) { prefix = argv[0]; p[1] = '\0'; }#ifdef STANDARD_EXEC_PREFIX else if (access (STANDARD_EXEC_PREFIX, X_OK) == 0) prefix = STANDARD_EXEC_PREFIX;#endif#ifdef MD_EXEC_PREFIX else if (access (MD_EXEC_PREFIX, X_OK) == 0) prefix = MD_EXEC_PREFIX;#endif else if (access ("/usr/ccs/gcc", X_OK) == 0) prefix = "/usr/ccs/gcc/"; else if (access ("/usr/ccs/bin", X_OK) == 0) prefix = "/usr/ccs/bin/"; else prefix = "/bin/"; } clen = len = strlen (prefix);#ifdef STANDARD_BIN_PREFIX if (clen < sizeof (STANDARD_BIN_PREFIX) - 1) clen = sizeof (STANDARD_BIN_PREFIX) - 1;#endif#ifdef STANDARD_EXEC_PREFIX if (clen < sizeof (STANDARD_EXEC_PREFIX) - 1) clen = sizeof (STANDARD_EXEC_PREFIX) - 1;#endif /* Allocate enough string space for the longest possible pathnames. */ ld_file_name = xcalloc (len + sizeof ("real-ld"), 1); nm_file_name = xcalloc (len + sizeof ("gnm"), 1); strip_file_name = xcalloc (len + sizeof ("gstrip"), 1); /* Determine the full path name of the ld program to use. */ bcopy (prefix, ld_file_name, len); strcpy (ld_file_name + len, "real-ld"); if (access (ld_file_name, X_OK) < 0) { strcpy (ld_file_name + len, "gld"); if (access (ld_file_name, X_OK) < 0) { free (ld_file_name);#ifdef REAL_LD_FILE_NAME ld_file_name = REAL_LD_FILE_NAME;#else ld_file_name = (access ("/usr/bin/ld", X_OK) == 0 ? "/usr/bin/ld" : "/bin/ld");#endif } } /* Determine the full path name of the C compiler to use. */ c_file_name = getenv ("COLLECT_GCC"); /* If this is absolute, it must be a file that exists. If it is relative, it must be something that execvp was able to find. Either way, we can pass it to execvp and find the same executable. */ if (c_file_name == 0) { c_file_name = xcalloc (clen + sizeof ("gcc"), 1); bcopy (prefix, c_file_name, len); strcpy (c_file_name + len, "gcc"); if (access (c_file_name, X_OK) < 0) {#ifdef STANDARD_BIN_PREFIX strcpy (c_file_name, STANDARD_BIN_PREFIX); strcat (c_file_name, "gcc"); if (access (c_file_name, X_OK) < 0)#endif {#ifdef STANDARD_EXEC_PREFIX strcpy (c_file_name, STANDARD_EXEC_PREFIX); strcat (c_file_name, "gcc"); if (access (c_file_name, X_OK) < 0)#endif { strcpy (c_file_name, "gcc"); } } } } /* Determine the full path name of the nm to use. */ bcopy (prefix, nm_file_name, len); strcpy (nm_file_name + len, "nm"); if (access (nm_file_name, X_OK) < 0) { strcpy (nm_file_name + len, "gnm"); if (access (nm_file_name, X_OK) < 0) { free (nm_file_name);#ifdef REAL_NM_FILE_NAME nm_file_name = REAL_NM_FILE_NAME;#else nm_file_name = (access ("/usr/bin/nm", X_OK) == 0 ? "/usr/bin/nm" : "/bin/nm");#endif } } /* Determine the full pathname of the strip to use. */ bcopy (prefix, strip_file_name, len); strcpy (strip_file_name + len, "strip"); if (access (strip_file_name, X_OK) < 0) { strcpy (strip_file_name + len, "gstrip"); if (access (strip_file_name, X_OK) < 0) { free (strip_file_name);#ifdef REAL_STRIP_FILE_NAME strip_file_name = REAL_STRIP_FILE_NAME;#else strip_file_name = (access ("/usr/bin/strip", X_OK) == 0 ? "/usr/bin/strip" : "/bin/strip");#endif } } *ld1++ = *ld2++ = "ld"; /* Make temp file names. */ choose_temp_base (); c_file = xcalloc (temp_filename_length + sizeof (".c"), 1); o_file = xcalloc (temp_filename_length + sizeof (".o"), 1); sprintf (c_file, "%s.c", temp_filename); sprintf (o_file, "%s.o", temp_filename); *c_ptr++ = c_file_name; *c_ptr++ = "-c"; *c_ptr++ = "-o"; *c_ptr++ = o_file; /* !!! When GCC calls collect2, it does not know whether it is calling collect2 or ld. So collect2 cannot meaningfully understand any options except those ld understands. If you propose to make GCC pass some other option, just imagine what will happen if ld is really ld!!! */ /* Parse arguments. Remember output file spec, pass the rest to ld. */ /* After the first file, put in the c++ rt0. */ first_file = 1; while ((arg = *++argv) != (char *)0) { *ld1++ = *ld2++ = arg; if (arg[0] == '-') switch (arg[1]) { case 'd': if (!strcmp (arg, "-debug")) { debug = 1; vflag = 1; ld1--; ld2--; } break; case 'o': outfile = (arg[2] == '\0') ? argv[1] : &arg[2]; break; case 'r': if (arg[2] == '\0') rflag = 1; break; case 's': if (arg[2] == '\0') { /* We must strip after the nm run, otherwise C++ linking won't work. Thus we strip in the second ld run, or else with strip if there is no second ld run. */ strip_flag = 1; ld1--; } break; case 'v': if (arg[2] == '\0') vflag = 1; break; } else if (first_file && (p = rindex (arg, '.')) != (char *)0 && strcmp (p, ".o") == 0) { first_file = 0; *ld2++ = o_file; } } /* Get any options that the upper GCC wants to pass to the sub-GCC. */ p = (char *) getenv ("COLLECT_GCC_OPTIONS"); if (p) while (*p) { char *q = p; while (*q && *q != ' ') q++; if (*p == '-' && (p[1] == 'm' || p[1] == 'f')) *c_ptr++ = savestring (p, q - p); if (*q) q++; p = q; } *c_ptr++ = c_file; *c_ptr = *ld1 = *ld2 = (char *)0; if (vflag) { fprintf (stderr, "collect2 version %s", version_string);#ifdef TARGET_VERSION TARGET_VERSION;#endif fprintf (stderr, "\n"); } if (debug) { char *ptr; fprintf (stderr, "prefix = %s\n", prefix); fprintf (stderr, "ld_file_name = %s\n", ld_file_name); fprintf (stderr, "c_file_name = %s\n", c_file_name); fprintf (stderr, "nm_file_name = %s\n", nm_file_name); fprintf (stderr, "c_file = %s\n", c_file); fprintf (stderr, "o_file = %s\n", o_file); ptr = getenv ("COLLECT_GCC_OPTIONS"); if (ptr) fprintf (stderr, "COLLECT_GCC_OPTIONS = %s\n", ptr); ptr = getenv ("COLLECT_GCC"); if (ptr) fprintf (stderr, "COLLECT_GCC = %s\n", ptr); ptr = getenv ("COMPILER_PATH"); if (ptr) fprintf (stderr, "COMPILER_PATH = %s\n", ptr); ptr = getenv ("LIBRARY_PATH"); if (ptr) fprintf (stderr, "LIBRARY_PATH = %s\n", ptr); fprintf (stderr, "\n"); } /* Load the program, searching all libraries. Examine the namelist with nm and search it for static constructors and destructors to call. Write the constructor and destructor tables to a .s file and reload. */ fork_execute (ld_file_name, ld1_argv); /* If -r, don't build the constructor or destructor list, just return now. */ if (rflag) return 0; scan_prog_file (outfile, PASS_FIRST); if (debug) { fprintf (stderr, "%d constructor(s) found\n", constructors.number); fprintf (stderr, "%d destructor(s) found\n", destructors.number); } if (constructors.number == 0 && destructors.number == 0) { /* Strip now if it was requested on the command line. */ if (strip_flag) { char **strip_argv = (char **) xcalloc (sizeof (char *), 3); strip_argv[0] = "strip"; strip_argv[1] = outfile; strip_argv[2] = (char *) 0; fork_execute (strip_file_name, strip_argv); } return 0; } outf = fopen (c_file, "w"); if (outf == (FILE *)0) fatal_perror ("%s", c_file); write_c_file (outf, c_file); if (fclose (outf)) fatal_perror ("closing %s", c_file); if (debug) { fprintf (stderr, "\n========== outfile = %s, c_file = %s\n", outfile, c_file); write_c_file (stderr, "stderr"); fprintf (stderr, "========== end of c_file\n\n"); } /* Assemble the constructor and destructor tables. Link the tables in with the rest of the program. */ fork_execute (c_file_name, c_argv); fork_execute (ld_file_name, ld2_argv); /* Let scan_prog_file do any final mods (OSF/rose needs this for constructors/destructors in shared libraries. */ scan_prog_file (outfile, PASS_SECOND); maybe_unlink (c_file); maybe_unlink (o_file); return 0;}/* Wait for a process to finish, and exit if a non-zero status is found. */static voiddo_wait (prog) char *prog;{ int status; wait (&status); if (status) { int sig = status & 0x7F; int ret; if (sig != -1 && sig != 0) {#ifdef NO_SYS_SIGLIST error ("%s terminated with signal %d %s", prog, sig, (status & 0200) ? ", core dumped" : "");#else error ("%s terminated with signal %d [%s]%s", prog, sig, sys_siglist[sig], (status & 0200) ? ", core dumped" : "");#endif my_exit (127); } ret = ((status & 0xFF00) >> 8); if (ret != -1 && ret != 0) { error ("%s returned %d exit status", prog, ret); my_exit (ret); } }}/* Fork and execute a program, and wait for the reply. */static voidfork_execute (prog, argv) char *prog; char **argv;{ int pid; if (vflag || debug) { char **p_argv; char *str; fprintf (stderr, "%s", prog); for (p_argv = &argv[1]; (str = *p_argv) != (char *)0; p_argv++) fprintf (stderr, " %s", str); fprintf (stderr, "\n"); } fflush (stdout); fflush (stderr); pid = vfork (); if (pid == -1) fatal_perror ("vfork"); if (pid == 0) /* child context */ { execvp (prog, argv); fatal_perror ("executing %s", prog); } do_wait (prog);}/* Unlink a file unless we are debugging. */static voidmaybe_unlink (file) char *file;{ if (!debug) unlink (file); else fprintf (stderr, "[Leaving %s]\n", file);}/* Add a name to a linked list. */static voidadd_to_list (head_ptr, name) struct head *head_ptr; char *name;{ struct id *newid = (struct id *) xcalloc (sizeof (*newid) + strlen (name), 1); static long sequence_number = 0; newid->sequence = ++sequence_number; strcpy (newid->name, name); if (head_ptr->first) head_ptr->last->next = newid; else head_ptr->first = newid; head_ptr->last = newid; head_ptr->number++;}/* Write: `prefix', the names on list LIST, `suffix'. */static voidwrite_list (stream, prefix, list) FILE *stream; char *prefix; struct id *list;{ while (list) { fprintf (stream, "%sx%d,\n", prefix, list->sequence); list = list->next; }}static void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -