1 /*
2  * Copyright (c) 2003 - 2010, Nils R. Weller
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  *
27  * Driver for cpp, nasm, ncc and ld
28  */
29 #include "driver.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/wait.h>
36 #include <unistd.h>
37 #include <assert.h>
38 #include "exectools.h"
39 #include "backend.h"
40 #include "misc.h"
41 #include "sysdeps.h"
42 #include "debug.h"
43 #include "cc_main.h"
44 #include "defs.h"
45 #include "n_libc.h"
46 
47 /*
48  * Store file path referenced by ``name'' in dynamically allocated variable
49  * *output_names, resize it if necessary (*output_index contains the
50  * number of files in use, it is incremented at each call. The variable keeping
51  * track of allocated members in *output_names is static.)
52  */
53 static int
store_file(char *** output_names,int ** output_del,int needdel,char * name,int * output_index)54 store_file(char ***output_names, int **output_del, int needdel,
55 char *name, int *output_index) {
56 
57 	static int	alloc = 0;
58 	static int	chunk_size =  8;
59 	int		tmpi = *output_index;
60 
61 	if (tmpi >= alloc) {
62 		alloc += chunk_size;
63 
64 		/* Quadratically increase number of allocated slots */
65 		chunk_size *= chunk_size;
66 
67 		*output_names =
68 			n_xrealloc(*output_names, alloc * sizeof(char *));
69 		*output_del =
70 			n_xrealloc(*output_del, alloc * sizeof **output_del);
71 
72 	}
73 	(*output_names)[tmpi] = n_xstrdup(name);
74 	(*output_del)[tmpi] = needdel;
75 	++(*output_index);
76 	return 0;
77 }
78 
79 extern int Sflag; /* XXX */
80 
81 int
driver(char ** cpp_flags,char * asm_flags,char * ld_flags,char ** files)82 driver(char **cpp_flags, char *asm_flags, char *ld_flags, char **files) {
83 	int			i;
84 	int			rc;
85 	int			out_index = 0;
86 	int			ld_cmd_len;
87 	int			has_errors = 0;
88 	int			sd_host_sys;
89 	char			*ld_cmd;
90 	char			**output_names = NULL;
91 	char			buf[256];
92 	int			*output_del = NULL;
93 	pid_t			pid;
94 	FILE			*fd;
95 	char			ld_std_flags[512];
96 	char			ld_pre_std_flags[128];
97 	static struct timeval	tv;
98 
99 	*ld_pre_std_flags = 0;
100 
101 	sd_host_sys = sysdep_get_host_system();
102 
103 
104 	if (archflag == ARCH_X86) {
105 		if (sd_host_sys == OS_FREEBSD) {
106 			sprintf(ld_std_flags,
107 				"-dynamic-linker /usr/libexec/ld-elf.so.1 "
108 				"%s /usr/lib/crti.o /usr/lib/crtbegin.o "
109 				"-L/usr/lib -lc /usr/lib/crtend.o /usr/lib/crtn.o ",
110 				sharedflag? "-shared": "/usr/lib/crt1.o");
111 		} else if (sd_host_sys == OS_DRAGONFLYBSD) {
112 			/*
113 			 * Uses same flags as FreeBSD except for ld-elf.so.2 instead
114 			 * of ld-elf.so.1
115 			 */
116 			sprintf(ld_pre_std_flags, sharedflag? "-shared": "/usr/lib/crt1.o");
117 			sprintf(ld_std_flags,
118 				"-dynamic-linker /usr/libexec/ld-elf.so.2 "
119 				"/usr/lib/crti.o /usr/lib/crtbegin.o "
120 				"-L/usr/lib -lc /usr/lib/crtend.o /usr/lib/crtn.o ");
121 		} else if (sd_host_sys == OS_MIRBSD) {
122 			/*
123 			 * 07/25/09: XXX Untested!
124 			 */
125 			sprintf(ld_pre_std_flags, sharedflag? "-shared /usr/lib/crtbeginS.o":
126 					"/usr/lib/crt0.o /usr/lib/crtbegin.o");
127 			sprintf(ld_std_flags, sharedflag?
128 /*			"-shared "*/
129 				"/usr/lib/crti.o "
130 				"/usr/lib/crtendS.o /usr/lib/crtn.o " :
131 				"-e __start -dynamic-linker /usr/libexec/ld.so "
132 				"/usr/lib/crti.o "
133 				"-lc /usr/lib/crtend.o /usr/lib/crtn.o ");
134 		} else if (sd_host_sys == OS_OPENBSD) {
135 			sprintf(ld_pre_std_flags, "/usr/lib/crt0.o /usr/lib/crtbegin.o");
136 			sprintf(ld_std_flags,
137 				"-e __start -Bdynamic -dynamic-linker "
138 				"/usr/libexec/ld.so"
139 				" -lc /usr/lib/crtend.o ");
140 		} else if (sd_host_sys == OS_NETBSD) {
141 			sprintf(ld_pre_std_flags, "/usr/lib/crt0.o /usr/lib/crtbegin.o");
142 			sprintf(ld_std_flags, "-dc -dp -e __start -dynamic-linker "
143 				"/usr/libexec/ld.elf_so /usr/lib/crti.o "
144 				"-lc /usr/lib/crtend.o /usr/lib/crtn.o ");
145 		} else if (sd_host_sys == OS_LINUX) {
146 #ifndef LIBDIR_32
147 #define LIBDIR_32 "/usr/lib/"
148 #define RTLDDIR_32 "/lib/"
149 #endif
150 			sprintf(ld_pre_std_flags, sharedflag? "": LIBDIR_32 "crt1.o");
151 			sprintf(ld_std_flags,
152 				"-lc %s " LIBDIR_32 "crti.o "
153 				LIBDIR_32 "crtn.o " LIBDIR_32 "libc.so "
154 				"--dynamic-linker " RTLDDIR_32 "ld-linux.so.2 ",
155 				sharedflag? "-shared": "");  /*"/usr/lib/crt1.o");*/
156 #undef LIBDIR_32
157 #undef RTLDDIR_32
158 		} else if (sd_host_sys == OS_SOLARIS) {
159 			sprintf(ld_pre_std_flags, sharedflag? "-shared": "/usr/lib/crt1.o");
160 			sprintf(ld_std_flags,
161 				"-L/usr/ccs/lib -L/usr/lib -Qy "
162 				"/usr/lib/crti.o -lc /usr/lib/crtn.o ");
163 		} else if (sd_host_sys == OS_OSX) {
164 			sprintf(ld_std_flags,
165 				"-dynamic -arch i386 -macosx_version_min 10.5.0 "
166 				"-weak_reference_mismatches non-weak -lcrt1.10.5.o "
167 				"-lSystem");
168 		} else {
169 			/* XXX */
170 			(void) fprintf(stderr, "This operating system isn't supported"
171 			      " on x86\n");
172 		}
173 	} else if (archflag == ARCH_AMD64) {
174 		if (sd_host_sys == OS_LINUX) {
175 			/*
176 			 * 08/08/07: Explicitly use lib64 instead of lib
177 			 * dirs, since some distributions seem to put 32bit
178 			 * files into plain lib dirs
179 			 *
180 			 * 07/24/12: Some 64bit distributions have moved the
181 			 * locations of library directories again. Specifically,
182 			 * KUbuntu AMD64 not only stores 64bit libs in /usr/lib,
183 			 * but also puts the CRT libs we're interested in into
184 			 * a sub directory titled "x86_64-linux-gnu".
185 			 * We use configure to attempt to make sense of this.
186 			 * XXX This should probably be stored in the config file
187 			 * instead.
188 			 */
189 #ifndef LIBDIR_64
190 #define LIBDIR_64 "/usr/lib64/"
191 #endif
192 #ifndef RTLDDIR_64
193 #define RTLDDIR_64 "/lib64/"
194 #endif
195 
196 			sprintf(ld_pre_std_flags, sharedflag? "-shared": LIBDIR_64 "crt1.o");
197 			sprintf(ld_std_flags, "-lc " LIBDIR_64 "crti.o "
198 				LIBDIR_64 "crtn.o " LIBDIR_64 "libc.so "
199 				"--dynamic-linker " RTLDDIR_64 "ld-linux-x86-64.so.2 ");
200 #undef LIBDIR64
201 #undef RTLDDIR_64
202 		} else if (sd_host_sys == OS_DRAGONFLYBSD) {
203 			sprintf(ld_pre_std_flags, sharedflag? "-shared": "/usr/lib/crt1.o");
204 			sprintf(ld_std_flags,
205 				"-dynamic-linker /usr/libexec/ld-elf.so.2 "
206 				"/usr/lib/crti.o /usr/lib/crtbegin.o "
207 				"-L/usr/lib -lc /usr/lib/crtend.o /usr/lib/crtn.o ");
208 		} else if (sd_host_sys == OS_FREEBSD) {
209 			sprintf(ld_pre_std_flags, sharedflag? "-shared": "/usr/lib/crt1.o");
210 			sprintf(ld_std_flags, "/usr/lib/crti.o "
211 			"/usr/lib/crtbegin.o -L/usr/lib -lc /usr/lib/crtend.o "
212 			"/usr/lib/crtn.o -dynamic-linker /libexec/ld-elf.so.1 ");
213 		} else if (sd_host_sys == OS_OPENBSD) {
214 			sprintf(ld_pre_std_flags, "/usr/lib/crt0.o /usr/lib/crtbegin.o");
215 			sprintf(ld_std_flags, "-Bdynamic "
216 				"-dynamic-linker /usr/libexec/ld.so "
217 				"-lc /usr/lib/crtend.o "
218 				"-L/usr/lib ");
219 		} else if (sd_host_sys == OS_OSX) {
220 			sprintf(ld_std_flags,
221 				"-dynamic -arch x86_64 -macosx_version_min 10.5.0 "
222 				"-weak_reference_mismatches non-weak -lcrt1.10.5.o "
223 				"-lSystem");
224 		} else {
225 			/* XXX */
226 			(void) fprintf(stderr, "This operating system isn't supported"
227 				      " on AMD64\n");
228 		}
229 	} else if (archflag == ARCH_MIPS) {
230 		if (sd_host_sys == OS_IRIX) {
231 			if (abiflag == ABI_MIPS_N64) {
232 				strcpy(ld_std_flags,
233 				"-64 /usr/lib64/mips3/crt1.o -L/usr/lib64/mips3 "
234 				"-L/usr/lib64 -lc /usr/lib64/mips3/crtn.o ");
235 			} else {
236 				strcpy(ld_std_flags,
237 					"/usr/lib32/crt1.o /usr/lib32/crtn.o "
238 					"/usr/lib32/bpcrt.o -lc ");
239 			}
240 		} else if (sd_host_sys == OS_LINUX) {
241 			if (abiflag == ABI_MIPS_N64) {
242 				sprintf(ld_pre_std_flags, sharedflag? "-shared": "/usr/lib64/crt1.o");
243 				strcpy(ld_std_flags,
244 					"-dynamic-linker /lib64/ld.so.1 -melf64ltsmip "
245 					"/usr/lib64/crti.o /usr/lib64/crtn.o "
246 					"-L/usr/lib64 -lc ");
247 			} else {
248 				sprintf(ld_pre_std_flags, sharedflag? "-shared": "/usr/lib64/crt1.o");
249 				strcpy(ld_std_flags,
250 					"-dynamic-linker /lib64/ld.so.1 -melf64ltsmip "
251 					"/usr/lib64/crti.o /usr/lib64/crtn.o "
252 					"-L/usr/lib64 -lc ");
253 			}
254 		} else {
255 			/* XXX */
256 			(void) fprintf(stderr, "This operating system isn't supported"
257 			      " on MIPS\n");
258 		}
259 	} else if (archflag == ARCH_POWER) {
260 		if (sd_host_sys == OS_AIX) {
261 			if (abiflag == ABI_POWER64) {
262 				strcpy(ld_std_flags,
263 					"-bpT:0x10000000 -bpD:0x20000000 -btextro -b64 "
264 					"/lib/crt0_64.o -L/usr/lib -lc ");
265 			} else {
266 				strcpy(ld_std_flags,
267 					"-bpT:0x10000000 -bpD:0x20000000 -btextro /lib/crt0.o -L/usr/lib -lc ");
268 			}
269 		} else if (sd_host_sys == OS_LINUX) {
270 			/*
271 			 * Because Linux/PPC64 appallingly does not provide crtbegin.o
272 			 * and crtend.o in standard places, even though they are needed
273 			 * by crt1.o, which IS provided in standard places, we have to
274 			 * use a private copy
275 			 */
276 			struct stat	sbuf;
277 			char		*crtbegin = NULL;
278 			char		*crtend = NULL;
279 
280 			if (abiflag == ABI_POWER64) {
281 				if (stat(INSTALLDIR "/nwcc/lib/crtbegin-64.o", &sbuf)==0) {
282 					crtbegin = INSTALLDIR "/nwcc/lib/crtbegin-64.o";
283 				} else if (stat("./crtbegin-64.o", &sbuf) == 0) {
284 					crtbegin = "./crtbegin-64.o";
285 				}
286 				if (stat(INSTALLDIR "/nwcc/lib/crtend-64.o", &sbuf)==0) {
287 					crtend = INSTALLDIR "/nwcc/lib/crtend-64.o";
288 				} else if (stat("./crtend-64.o", &sbuf) == 0) {
289 					crtend = "./crtend-64.o";
290 				}
291 			} else if (sysflag == OS_LINUX) {
292 				(void) fprintf(stderr,
293 		"ERROR: 32bit mode not implemented for Linux/PPC! Please \n"
294 		"       contact the author to donate a 32bit account or a\n"
295 		"       64bit account with 32bit gcc and libraries.\n");
296 				crtbegin = "";
297 				crtend = "";
298 
299 	#if 0
300 				/* 32bit */
301 				if (stat(INSTALLDIR "/nwcc/lib/crtbegin-32.o", &sbuf)==0) {
302 					crtbegin = INSTALLDIR "/nwcc/lib/crtbegin-32.o";
303 				} else if (stat("./crtbegin-32.o", &sbuf) == 0) {
304 					crtbegin = "./crtbegin-32.o";
305 				}
306 				if (stat(INSTALLDIR "/nwcc/lib/crtend-32.o", &sbuf)==0) {
307 					crtend = INSTALLDIR "/nwcc/lib/crtend-32.o";
308 				} else if (stat("./crtend-32.o", &sbuf) == 0) {
309 					crtend = "./crtend-32.o";
310 				}
311 	#endif
312 			}
313 
314 			if (!Sflag) {
315 				if (crtbegin == NULL) {
316 					(void) fprintf(stderr, "Warning: No crtbegin object found "
317 						"in " INSTALLDIR "/nwcc/lib or .!\n");
318 					crtbegin = "";
319 				}
320 				if (crtend == NULL) {
321 					(void) fprintf(stderr, "Warning: No crtend object found "
322 						"in " INSTALLDIR "/nwcc/lib or .!\n");
323 					crtend = "";
324 				}
325 				if (abiflag == ABI_POWER64) {
326 					sprintf(ld_pre_std_flags, "/usr/lib64/crt1.o %s",
327 						crtbegin);
328 					sprintf(ld_std_flags, "--eh-frame-hdr -Qy -m elf64ppc "
329 						"-dynamic-linker /lib64/ld64.so.1 "
330 						"-L/lib64 -L/usr/lib64 "
331 						"/usr/lib64/crti.o /usr/lib64/crtn.o -lc %s",
332 						crtend);
333 				} else {
334 					unimpl();
335 				}
336 			}
337 		} else {
338 			/* XXX */
339 			(void) fprintf(stderr, "This operating system isn't supported"
340 			      " on PPC\n");
341 		}
342 	} else if (archflag == ARCH_SPARC) {
343 		if (sd_host_sys == OS_LINUX) {
344 			sprintf(ld_pre_std_flags, "/usr/lib64/crt1.o");
345 			strcpy(ld_std_flags, "-m elf64_sparc -Y P,/usr/lib64 "
346 				"-dynamic-linker /lib64/ld-linux.so.2 "
347 				"-L/lib64 -L/usr/lib64 "
348 				"/usr/lib64/crti.o /usr/lib64/crtn.o -lc ");
349 		} else if (sd_host_sys == OS_MIRBSD) {
350 			/* XXX Untested! */
351 			sprintf(ld_pre_std_flags, sharedflag? "-shared /usr/lib/crtbeginS.o":
352 					"/usr/lib/crt0.o /usr/lib/crtbegin.o");
353 			sprintf(ld_std_flags, sharedflag ?
354 				"/usr/lib/crti.o "
355 				"/usr/lib/crtendS.o /usr/lib/crtn.o " :
356 				"-e __start -dynamic-linker /usr/libexec/ld.so "
357 				"/usr/lib/crti.o "
358 				"-lc /usr/lib/crtend.o /usr/lib/crtn.o ");
359 		} else if (sd_host_sys == OS_SOLARIS) {
360 			/*
361 			 * Because Solaris/SPARC does not ship with crt1.o, we
362 			 * use our own
363 			 */
364 			struct stat	sbuf;
365 			char		*crt1 = NULL;
366 
367 			if (abiflag == ABI_SPARC64) {
368 				if (stat(INSTALLDIR "/nwcc/lib/crt1-64.o", &sbuf)==0) {
369 					crt1 = INSTALLDIR "/nwcc/lib/crt1-64.o";
370 				} else if (stat("./crt1-64.o", &sbuf) == 0) {
371 					crt1 = "./crt1-64.o";
372 				}
373 			} else {
374 				/* 32bit */
375 				if (stat(INSTALLDIR "/nwcc/lib/crt1-32.o", &sbuf)==0) {
376 					crt1 = INSTALLDIR "/nwcc/lib/crt1-324.o";
377 				} else if (stat("./crt1-32.o", &sbuf) == 0) {
378 					crt1 = "./crt1-32.o";
379 				}
380 			}
381 			if (crt1 == NULL) {
382 				(void) fprintf(stderr, "Warning: No crt1 object found "
383 					"in " INSTALLDIR "/nwcc/lib or .!\n");
384 				crt1 = "";
385 			}
386 
387 			if (abiflag == ABI_SPARC64) {
388 				/*
389 				 * /usr/local/lib/gcc/sparc-sun-solaris2.10/3.4.6/crt1.o
390 				                                                /sparcv9/crt1.o*/
391 				sprintf(ld_std_flags,
392 					"/usr/lib/sparcv9/crti.o /usr/lib/sparcv9/crtn.o %s "
393 					"-Y \"P,/usr/ccs/lib/sparcv9:/lib/sparcv9"
394 					":/usr/lib/sparcv9\" %s ",
395 					sharedflag? "-G -dy -z text": crt1,
396 					sharedflag? "": "-lc");
397 			} else {
398 				sprintf(ld_std_flags,
399 					"/usr/lib/crti.o /usr/lib/crtn.o %s "
400 					"-Y \"P,/usr/ccs/lib:/lib:/usr/lib\" -lc ",
401 					crt1);
402 			}
403 		} else {
404 			/* XXX */
405 			(void) fprintf(stderr, "This operating system isn't supported"
406 			      " on SPARC\n");
407 		}
408 	} else {
409 		unimpl();
410 	}
411 
412 	for (i = 0; files[i] != NULL; ++i) {
413 		char	*p = strrchr(files[i], '.');
414 		char	*p2;
415 		int	needdel = 1;
416 
417 
418 		/*
419 		 * 02/09/08: Check whether this is really a file (as
420 		 * opposed to a command line option parameter)
421 		 */
422 		if (files[i][0] == '-') {
423 			continue;
424 		} else if (argmap[i] && !write_fcat_flag) {
425 			continue;
426 		}
427 
428 		/* Ignore files without appropriate extension */
429 		if (p == NULL) {
430 			continue;
431 		}
432 		++p;
433 
434 		/*
435 		 * Determine file type to decide which tools (cpp, nasm, ld)
436 		 * have to be invoked.
437 		 */
438 #if 0
439 		if (assembler == ASM_GAS
440 			|| archflag == ARCH_MIPS
441 			|| archflag == ) {
442 #endif
443 			{
444 
445 
446 			/*
447 			 * gas doesn't do foo.c -> foo.o by default. It calls
448 			 * the output a.out. *barf*
449 			 * XXX This is kludged
450 			 */
451 			static char	*out_ptr;
452 			char		*filep;
453 
454 			if ((filep = strrchr(files[i], '/')) != NULL) {
455 				++filep;
456 			} else {
457 				filep = files[i];
458 			}
459 
460 			if (!cflag || !oflag) {
461 				if (out_ptr == NULL) {
462 					out_ptr = strchr(asm_flags, 0);
463 				}
464 				sprintf(out_ptr, " -o %.*s.o",
465 					(int)(p - filep - 1), filep);
466 			}
467 			}
468 #if 0
469 		}
470 #endif
471 
472 		if (strcmp(p, "c") == 0 || strcmp(p, "i") == 0) {
473 			p2 = files[i];
474 
475 #ifdef DEBUG
476 			printf("Preprocessed successfully as %s\n", p2);
477 #endif
478 
479 			/* Compile file ``p2''. */
480 			if ((pid = fork()) == -1) {
481 				perror("fork");
482 				exit(EXIT_FAILURE);
483 			} else if (pid == 0) {
484 				char	*nwcc1_args[512]; /* XXX */
485 				char	*arch = NULL;
486 				int	j = 0;
487 				int	k = 0;
488 
489 				nwcc1_args[j++] = "nwcc1";
490 				if (stackprotectflag) {
491 					nwcc1_args[j++] = "-stackprotect";
492 				}
493 				if (gnuc_version) {
494 					static char	gnubuf[128];
495 					sprintf(gnubuf, "-gnuc=%s",
496 						gnuc_version);
497 					nwcc1_args[j++] = gnubuf;
498 				}
499 				if (std_flag != NULL) {
500 					static char	std[16];
501 					sprintf(std, "-std=%s", std_flag);
502 					nwcc1_args[j++] = std;
503 				}
504 				if (pedanticflag) {
505 					nwcc1_args[j++] = "-pedantic";
506 				}
507 				if (verboseflag) {
508 					nwcc1_args[j++] = "-verbose";
509 				}
510 				if (nostdinc_flag) {
511 					nwcc1_args[j++] = "-nostdinc";
512 				}
513 				if (picflag) {
514 					nwcc1_args[j++] = "-fpic";
515 				}
516 				if (fulltocflag || (!mintocflag && !fulltocflag)) {
517 					nwcc1_args[j++] = "-mfull-toc";
518 				} else {
519 					nwcc1_args[j++] = "-mminimal-toc";
520 				}
521 				if (stupidtraceflag) {
522 					nwcc1_args[j++] = "-stupidtrace";
523 				}
524 
525 
526 				if (gflag) {
527 					nwcc1_args[j++] = "-g";
528 				}
529 				if (Eflag) {
530 					nwcc1_args[j++] = "-E";
531 				}
532 				if (Oflag) {
533 					static char	obuf[16];
534 					sprintf(obuf, "-O%d", Oflag);
535 					nwcc1_args[j++] = obuf;
536 				}
537 				if (write_fcat_flag) {
538 					nwcc1_args[j++] = "-write-fcat";
539 				}
540 				if (save_bad_translation_unit_flag) {
541 					nwcc1_args[j++] = "-save-bad-translation-unit";
542 				}
543 
544 				/* XXX this should go into misc.c */
545 				switch (archflag) {
546 				case ARCH_X86:
547 					arch = "-arch=x86";
548 					break;
549 				case ARCH_AMD64:
550 					arch = "-arch=amd64";
551 					break;
552 				case ARCH_POWER:
553 					arch = "-arch=ppc";
554 					break;
555 				case ARCH_MIPS:
556 					if (get_target_endianness() == ENDIAN_LITTLE) {
557 						arch = "-arch=mipsel";
558 					} else {
559 						arch = "-arch=mips";
560 					}
561 					break;
562 				case ARCH_SPARC:
563 					arch = "-arch=sparc";
564 					break;
565 				case ARCH_PA:
566 				case ARCH_ARM:
567 				case ARCH_SH:
568 					unimpl();
569 				}
570 				nwcc1_args[j++] = arch;
571 
572 				if (abiflag != abiflag_default) {
573 					if (abiflag != 0) {
574 						nwcc1_args[j++] = /*abi*/
575 							abi_to_option(abiflag);
576 					}
577 				}
578 
579 				if (sysflag != sysflag_default) {
580 					if (sysflag != 0) {
581 						nwcc1_args[j++] = sys_to_option(sysflag);
582 					}
583 				}
584 
585 				if (asmflag) {
586 					nwcc1_args[j] =
587 						n_xmalloc(strlen(asmflag)+16);
588 					sprintf(nwcc1_args[j++],
589 						"-asm=%s", asmflag);
590 				}
591 				if (cppflag) {
592 					nwcc1_args[j] =
593 						n_xmalloc(strlen(cppflag+16));
594 					sprintf(nwcc1_args[j++],
595 						"-cpp=%s", cppflag);
596 				}
597 				if (timeflag) {
598 					nwcc1_args[j++] = n_xstrdup("-time");
599 				}
600 				if (funsignedchar_flag) {
601 					nwcc1_args[j++] = n_xstrdup("-funsigned-char");
602 				}
603 				if (fsignedchar_flag) {
604 					nwcc1_args[j++] = n_xstrdup("-fsigned-char");
605 				}
606 				if (fnocommon_flag) {
607 					nwcc1_args[j++] = n_xstrdup("-fno-common");
608 				}
609 				if (notgnu_flag) {
610 					nwcc1_args[j++] = n_xstrdup("-notgnu");
611 				} else {
612 					nwcc1_args[j++] = n_xstrdup("-gnu");
613 				}
614 				if (color_flag) {
615 					nwcc1_args[j++] = n_xstrdup("-color");
616 				}
617 				if (dump_macros_flag) {
618 					nwcc1_args[j++] = n_xstrdup("-dM");
619 				}
620 
621 				if (custom_cpp_args) {
622 					nwcc1_args[j++] = custom_cpp_args;
623 				}
624 
625 				nwcc1_args[j++] = p2;
626 				for (; cpp_flags[k] != NULL; ++j, ++k) {
627 					nwcc1_args[j] = cpp_flags[k];
628 				}
629 				nwcc1_args[j] = NULL;
630 #define DEVEL
631 #ifdef DEVEL
632 				execv("./nwcc1", nwcc1_args);
633 #endif
634 
635 				if ((p = getenv("NWCC_CC1")) != NULL) {
636 					execv(p, nwcc1_args);
637 					perror(p);
638 				} else {
639 #if 0
640 					execv("/usr/local/bin/nwcc1",
641 						nwcc1_args);
642 					perror("/usr/local/bin/nwcc1");
643 #endif
644 					execv(INSTALLDIR "/bin/nwcc1",
645 						nwcc1_args);
646 					perror(INSTALLDIR "/bin/nwcc1");
647 				}
648 				exit(EXIT_FAILURE);
649 			} else {
650 				if (waitpid(pid, &rc, 0) == -1) {
651 					perror("waitpid");
652 					exit(EXIT_FAILURE);
653 				}
654 				if (dump_macros_flag) {
655 					/*
656 					 * 05/19/09: -dM
657 					 */
658 					exit(EXIT_SUCCESS);
659 				}
660 				if (rc != 0) {
661 					/* Try other files anyway */
662 					has_errors = 1;
663 					continue;
664 				}
665 			}
666 
667 			/*
668 			 * nwcc just outputs with the same name as the input,
669 			 * except that the ending is .asm instead of .cpp
670 			 */
671 #ifdef DEBUG
672 			printf("Compiled successfully as %s\n", p2);
673 #endif
674 
675 			if (Sflag || Eflag || write_fcat_flag) {
676 				continue;
677 			}
678 
679 			p = p2;
680 			p2 = n_xmalloc(strlen(p2) + sizeof ".asm");
681 			strcpy(p2, p);
682 			p = strrchr(p2, '.');
683 			strcpy(++p, "asm");
684 
685 			/* Hopefully p2 is a valid .asm file now... */
686 			if (timeflag) {
687 				start_timer(&tv);
688 			}
689 
690 			if ((p = strrchr(p2, '/')) != NULL) {
691 				char	*saved = p+1;
692 				p2 = do_asm(p+1, asm_flags, abiflag);
693 				remove(saved);
694 			} else {
695 				char	*saved_p2 = p2;
696 				p2 = do_asm(p2, asm_flags, abiflag);
697 				remove(saved_p2);
698 			}
699 			if (p2 == NULL) {
700 				/* Ignore failure, try other files anyway. */
701 				continue;
702 			}
703 
704 			if (timeflag) {
705 				int	res = stop_timer(&tv);
706 				(void) fprintf(stderr,
707 					"=== Timing for assembling ===\n");
708 				(void) fprintf(stderr,
709 					"    %f sec\n", res / 1000000.0);
710 			}
711 
712 #ifdef DEBUG
713 			printf("Assembled successfully as %s\n", p2);
714 #endif
715 		} else if (strcmp(p, "asm") == 0) {
716 			p2 = do_asm(files[i], asm_flags, abiflag);
717 			if (p2 == NULL) {
718 				/* Ignore failure, try other files anyway. */
719 				continue;
720 			}
721 		} else if (strcmp(p, "o") == 0
722 			|| strcmp(p, "a") == 0
723 			|| strcmp(p, "so") == 0) {
724 			/*
725 			 * Don't do anything, the name is later just
726 			 * stored for ld because it is an object,
727 			 * library archive or shared library file
728 			 */
729 			p2 = files[i];
730 			needdel = 0;
731 		} else {
732 			continue;
733 		}
734 
735 		/*
736 		 * File ought to be compiled and assembled fine. Store path for
737 		 * later ld invocation
738 		 */
739 		if (store_file(&output_names, &output_del,
740 				needdel, p2, &out_index) != 0) {
741 			fprintf(stderr, "Exiting.\n");
742 			return 1;
743 		}
744 	}
745 
746 	if (i == 0) {
747 		fprintf(stderr, "Missing input files.\n");
748 		return 1;
749 	}
750 
751 	if (cflag || Sflag || Eflag || write_fcat_flag) return has_errors;
752 
753 	if (output_names == NULL) {
754 		fprintf(stderr, "No valid files to link.\n");
755 		return 1;
756 	}
757 
758 	/* Count length of all files plus white spaces and ld flags */
759 	ld_cmd_len = 0;
760 	for (i = 0; i < out_index; ++i) {
761 		ld_cmd_len += strlen(output_names[i]);
762 		++ld_cmd_len; /* white space */
763 	}
764 	ld_cmd_len += strlen(ld_flags);
765 	ld_cmd = malloc(sizeof "ld " + ld_cmd_len + 1 + sizeof ld_std_flags
766 		+ (custom_ld_args != NULL? strlen(custom_ld_args) + 3: 0)
767 		+ (xlinker_args != NULL? strlen(xlinker_args) + 3: 0));
768 	if (ld_cmd == NULL) {
769 		perror("malloc");
770 		return 1;
771 	}
772 
773 	if (archflag == ARCH_SPARC) {
774 		if (sd_host_sys == OS_LINUX) {
775 			strcpy(ld_cmd, "ld ");
776 		} else {
777 			/* Solaris */
778 			if (abiflag == ABI_SPARC64) {
779 				strcpy(ld_cmd, "/usr/ccs/bin/sparcv9/ld ");
780 			} else {
781 				strcpy(ld_cmd, "/usr/ccs/bin/ld ");
782 			}
783 		}
784 	} else {
785 		strcpy(ld_cmd, "ld ");
786 	}
787 
788 
789 	/*
790 	 * 07/02/09: CRT modules (and possibly other things) which should be
791 	 * put at the beginning of the link line
792 	 */
793 	strcat(ld_cmd, ld_pre_std_flags);
794 	strcat(ld_cmd, " ");
795 
796 	for (i = 0; i < out_index; ++i) {
797 		strcat(ld_cmd, output_names[i]);
798 		strcat(ld_cmd, " ");
799 	}
800 
801 	/*
802 	 * 11/23/07: Whoops, guess user-defined flags must come before
803 	 * standard ones (XXX are there exceptions?) because otherwise
804 	 * things like dummy library stubs in libc.so are given
805 	 * precedence over user-supplied libraries such as -lpthread or
806 	 * -lrt
807 	 */
808 	strcat(ld_cmd, ld_flags);
809 	strcat(ld_cmd, " ");
810 	strcat(ld_cmd, ld_std_flags);
811 	if (custom_ld_args != NULL) {
812 		char	*p;
813 
814 		/*
815 		 * Strip commas;
816 		 *
817 		 *    -Wl,-foo,-bar,-baz
818 		 *
819 		 * turns into
820 		 *
821 		 *    -foo -bar -baz
822 		 */
823 		for (p = custom_ld_args; *p != 0; ++p) {
824 			if (*p == ',') {
825 				*p = ' ';
826 			}
827 		}
828 		strcat(ld_cmd, " ");
829 		strcat(ld_cmd, custom_ld_args);
830 	}
831 	if (xlinker_args != NULL) {
832 		strcat(ld_cmd, " ");
833 		strcat(ld_cmd, xlinker_args);
834 	}
835 
836 
837 	if (timeflag) {
838 		start_timer(&tv);
839 	}
840 
841 	if (verboseflag) {
842 		printf("Running: %s\n", ld_cmd);
843 	}
844 	fd = popen(ld_cmd, "r");
845 	if (fd == NULL) {
846 		perror("popen");
847 		return 1;
848 	}
849 	while (fgets(buf, sizeof buf, fd)) {
850 		printf("%s", buf);
851 	}
852 
853 	if (timeflag) {
854 		int	res = stop_timer(&tv);
855 		(void) fprintf(stderr, "=== Timing of linking ===\n");
856 		(void) fprintf(stderr, "  %f sec\n", res / 1000000.0);
857 	}
858 
859 	for (i = 0; i < out_index; ++i) {
860 		if (output_del[i]) {
861 			remove(output_names[i]);
862 		}
863 	}
864 	rc = pclose(fd);
865 	if (WIFEXITED(rc)) {
866 		rc = WEXITSTATUS(rc);
867 		if (rc != 0) {
868 			has_errors = 1;
869 		} else {
870 			if (sflag) {
871 				/*
872 				 * Strip. Note that this is only done here;
873 				 * i.e. when building an executable file.
874 				 * When doing ``nwcc -c foo.c -s'', the
875 				 * flag is silently ignored, just like in
876 				 * gcc
877 				 */
878 				if ((fd = exec_cmd(1, "strip", " %s", out_file)) != NULL) {
879 					rc = pclose(fd);
880 					if (!WIFEXITED(rc)
881 						|| WEXITSTATUS(rc) != 0) {
882 						has_errors = 1;
883 					}
884 				} else {
885 					has_errors = 1;
886 				}
887 			}
888 		}
889 	} else {
890 		has_errors = 1;
891 	}
892 	return has_errors /*|| ((unsigned)pclose(fd) >> 8)*/ ; /* XXX !!! */
893 }
894 
895