10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57064Sab196087 * Common Development and Distribution License (the "License").
67064Sab196087 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
219291SGeorge.Vasick@Sun.COM
220Sstevel@tonic-gate /*
23*11997SScott.Rotondo@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate * Wrapper for the GNU assembler to make it accept the Sun assembler
290Sstevel@tonic-gate * arguments where possible.
300Sstevel@tonic-gate *
310Sstevel@tonic-gate * There are several limitations; the Sun assembler takes multiple
320Sstevel@tonic-gate * source files, we only take one.
330Sstevel@tonic-gate *
340Sstevel@tonic-gate * -b, -s, -xF, -T plain not supported.
350Sstevel@tonic-gate * -S isn't supported either, because while GNU as does generate
360Sstevel@tonic-gate * listings with -a, there's no obvious mapping between sub-options.
370Sstevel@tonic-gate * -K pic, -K PIC not supported either, though it's not clear what
380Sstevel@tonic-gate * these actually do ..
390Sstevel@tonic-gate * -Qy (not supported) adds a string to the .comment section
400Sstevel@tonic-gate * describing the assembler version, while
410Sstevel@tonic-gate * -Qn (supported) suppresses the string (also the default).
420Sstevel@tonic-gate *
430Sstevel@tonic-gate * We also add '-#' support to see invocation lines..
440Sstevel@tonic-gate * We also add '-xarch=amd64' in case we need to feed the assembler
450Sstevel@tonic-gate * something different (or in case we need to invoke a different binary
460Sstevel@tonic-gate * altogether!)
470Sstevel@tonic-gate */
480Sstevel@tonic-gate
490Sstevel@tonic-gate #include <sys/types.h>
500Sstevel@tonic-gate #include <sys/wait.h>
510Sstevel@tonic-gate #include <stdio.h>
520Sstevel@tonic-gate #include <unistd.h>
530Sstevel@tonic-gate #include <string.h>
540Sstevel@tonic-gate #include <stdlib.h>
557064Sab196087 #include <sys/param.h>
560Sstevel@tonic-gate
570Sstevel@tonic-gate static const char *progname;
580Sstevel@tonic-gate static int verbose;
590Sstevel@tonic-gate
600Sstevel@tonic-gate struct aelist {
610Sstevel@tonic-gate int ael_argc;
620Sstevel@tonic-gate struct ae {
630Sstevel@tonic-gate struct ae *ae_next;
640Sstevel@tonic-gate char *ae_arg;
650Sstevel@tonic-gate } *ael_head, *ael_tail;
660Sstevel@tonic-gate };
670Sstevel@tonic-gate
680Sstevel@tonic-gate static struct aelist *
newael(void)690Sstevel@tonic-gate newael(void)
700Sstevel@tonic-gate {
710Sstevel@tonic-gate return (calloc(sizeof (struct aelist), 1));
720Sstevel@tonic-gate }
730Sstevel@tonic-gate
740Sstevel@tonic-gate static void
newae(struct aelist * ael,const char * arg)750Sstevel@tonic-gate newae(struct aelist *ael, const char *arg)
760Sstevel@tonic-gate {
770Sstevel@tonic-gate struct ae *ae;
780Sstevel@tonic-gate
790Sstevel@tonic-gate ae = calloc(sizeof (*ae), 1);
800Sstevel@tonic-gate ae->ae_arg = strdup(arg);
810Sstevel@tonic-gate if (ael->ael_tail == NULL)
820Sstevel@tonic-gate ael->ael_head = ae;
830Sstevel@tonic-gate else
840Sstevel@tonic-gate ael->ael_tail->ae_next = ae;
850Sstevel@tonic-gate ael->ael_tail = ae;
860Sstevel@tonic-gate ael->ael_argc++;
870Sstevel@tonic-gate }
880Sstevel@tonic-gate
890Sstevel@tonic-gate static void
fixae_arg(struct ae * ae,const char * newarg)900Sstevel@tonic-gate fixae_arg(struct ae *ae, const char *newarg)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate free(ae->ae_arg);
930Sstevel@tonic-gate ae->ae_arg = strdup(newarg);
940Sstevel@tonic-gate }
950Sstevel@tonic-gate
960Sstevel@tonic-gate static char **
aeltoargv(struct aelist * ael)970Sstevel@tonic-gate aeltoargv(struct aelist *ael)
980Sstevel@tonic-gate {
990Sstevel@tonic-gate struct ae *ae;
1000Sstevel@tonic-gate char **argv;
1010Sstevel@tonic-gate int argc;
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate argv = calloc(sizeof (*argv), ael->ael_argc + 1);
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate for (argc = 0, ae = ael->ael_head; ae; ae = ae->ae_next, argc++) {
1060Sstevel@tonic-gate argv[argc] = ae->ae_arg;
1070Sstevel@tonic-gate if (ae == ael->ael_tail)
1080Sstevel@tonic-gate break;
1090Sstevel@tonic-gate }
1100Sstevel@tonic-gate
1110Sstevel@tonic-gate return (argv);
1120Sstevel@tonic-gate }
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate static int
error(const char * arg)1150Sstevel@tonic-gate error(const char *arg)
1160Sstevel@tonic-gate {
1170Sstevel@tonic-gate (void) fprintf(stderr,
1180Sstevel@tonic-gate "%s: as->gas mapping failed at or near arg '%s'\n", progname, arg);
1190Sstevel@tonic-gate return (2);
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate
1220Sstevel@tonic-gate static int
usage(const char * arg)1230Sstevel@tonic-gate usage(const char *arg)
1240Sstevel@tonic-gate {
1250Sstevel@tonic-gate if (arg != NULL)
1260Sstevel@tonic-gate (void) fprintf(stderr, "error: %s\n", arg);
1270Sstevel@tonic-gate (void) fprintf(stderr, "Usage: %s [-V] [-#]\n"
1280Sstevel@tonic-gate "\t[-xarch=architecture]\n"
1290Sstevel@tonic-gate "\t[-o objfile] [-L]\n"
1300Sstevel@tonic-gate "\t[-P [[-Ipath] [-Dname] [-Dname=def] [-Uname]]...]\n"
1310Sstevel@tonic-gate "\t[-m] [-n] file.s ...\n", progname);
1320Sstevel@tonic-gate return (3);
1330Sstevel@tonic-gate }
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate static void
copyuntil(FILE * in,FILE * out,int termchar)1360Sstevel@tonic-gate copyuntil(FILE *in, FILE *out, int termchar)
1370Sstevel@tonic-gate {
1380Sstevel@tonic-gate int c;
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate while ((c = fgetc(in)) != EOF) {
1410Sstevel@tonic-gate if (out && fputc(c, out) == EOF)
1420Sstevel@tonic-gate exit(1);
1430Sstevel@tonic-gate if (c == termchar)
1440Sstevel@tonic-gate break;
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate /*
1497064Sab196087 * Variant of copyuntil(), used for copying the path used
1507064Sab196087 * for .file directives. This version removes the workspace
1517064Sab196087 * from the head of the path, or failing that, attempts to remove
1527064Sab196087 * /usr/include. This is a workaround for the way gas handles
1537064Sab196087 * these directives. The objects produced by gas contain STT_FILE
1547064Sab196087 * symbols for every .file directive. These FILE symbols contain our
1557064Sab196087 * workspace paths, leading to wsdiff incorrectly flagging them as
1567064Sab196087 * having changed. By clipping off the workspace from these paths,
1577064Sab196087 * we eliminate these false positives.
1587064Sab196087 */
1597064Sab196087 static void
copyuntil_path(FILE * in,FILE * out,int termchar,const char * wspace,size_t wspace_len)1607064Sab196087 copyuntil_path(FILE *in, FILE *out, int termchar,
1617064Sab196087 const char *wspace, size_t wspace_len)
1627064Sab196087 {
1637064Sab196087 #define PROTO_INC "/proto/root_i386/usr/include/"
1647064Sab196087 #define SYS_INC "/usr/include/"
1657064Sab196087
1667199Sab196087 static const size_t proto_inc_len = sizeof (PROTO_INC) - 1;
1677199Sab196087 static const size_t sys_inc_len = sizeof (SYS_INC) - 1;
1687064Sab196087
1697064Sab196087 /*
1707064Sab196087 * Dynamically sized buffer for reading paths. Retained
1717064Sab196087 * and reused between calls.
1727064Sab196087 */
1737199Sab196087 static char *buf = NULL;
1747199Sab196087 static size_t bufsize = 0;
1757064Sab196087
1767199Sab196087 size_t bufcnt = 0;
1777064Sab196087 char *bufptr;
1787064Sab196087 int c;
1797064Sab196087
1807064Sab196087 /* Read the path into the buffer */
1817064Sab196087 while ((c = fgetc(in)) != EOF) {
1827064Sab196087 /*
1837064Sab196087 * If we need a buffer, or need a larger buffer,
1847064Sab196087 * fix that here.
1857064Sab196087 */
1867064Sab196087 if (bufcnt >= bufsize) {
1877199Sab196087 bufsize = (bufsize == 0) ? MAXPATHLEN : (bufsize * 2);
1887064Sab196087 buf = realloc(buf, bufsize + 1); /* + room for NULL */
1897064Sab196087 if (buf == NULL) {
1907064Sab196087 perror("realloc");
1917064Sab196087 exit(1);
1927064Sab196087 }
1937064Sab196087 }
1947064Sab196087
1957064Sab196087 buf[bufcnt++] = c;
1967064Sab196087 if (c == termchar)
1977064Sab196087 break;
1987064Sab196087 }
1997064Sab196087 if (bufcnt == 0)
2007064Sab196087 return;
2017064Sab196087
2027064Sab196087 /*
2037064Sab196087 * We have a non-empty buffer, and thus the opportunity
2047064Sab196087 * to do some surgery on it before passing it to the output.
2057064Sab196087 */
2067064Sab196087 buf[bufcnt] = '\0';
2077064Sab196087 bufptr = buf;
2087064Sab196087
2097064Sab196087 /*
2107064Sab196087 * If our workspace is at the start, remove it.
2117064Sab196087 * If not, then look for the system /usr/include instead.
2127064Sab196087 */
2137064Sab196087 if ((wspace_len > 0) && (wspace_len < bufcnt) &&
2147064Sab196087 (strncmp(bufptr, wspace, wspace_len) == 0)) {
2157064Sab196087 bufptr += wspace_len;
2167064Sab196087 bufcnt -= wspace_len;
2177064Sab196087
2187064Sab196087 /*
2197064Sab196087 * Further opportunity: Also clip the prefix
2207064Sab196087 * that leads to /usr/include in the proto.
2217064Sab196087 */
2227064Sab196087 if ((proto_inc_len < bufcnt) &&
2237064Sab196087 (strncmp(bufptr, PROTO_INC, proto_inc_len) == 0)) {
2247064Sab196087 bufptr += proto_inc_len;
2257064Sab196087 bufcnt -= proto_inc_len;
2267064Sab196087 }
2277064Sab196087 } else if ((sys_inc_len < bufcnt) &&
2287064Sab196087 (strncmp(bufptr, SYS_INC, sys_inc_len) == 0)) {
2297064Sab196087 bufptr += sys_inc_len;
2307064Sab196087 bufcnt -= sys_inc_len;
2317064Sab196087 }
2327064Sab196087
2337064Sab196087 /* Output whatever is left */
2347064Sab196087 if (out && (fwrite(bufptr, 1, bufcnt, out) != bufcnt)) {
2357064Sab196087 perror("fwrite");
2367064Sab196087 exit(1);
2377064Sab196087 }
2387064Sab196087
2397064Sab196087 #undef PROTO_INC
2407064Sab196087 #undef SYS_INC
2417064Sab196087 }
2427064Sab196087
2437064Sab196087 /*
2440Sstevel@tonic-gate * The idea here is to take directives like this emitted
2450Sstevel@tonic-gate * by cpp:
2460Sstevel@tonic-gate *
2470Sstevel@tonic-gate * # num
2480Sstevel@tonic-gate *
2490Sstevel@tonic-gate * and convert them to directives like this that are
2500Sstevel@tonic-gate * understood by the GNU assembler:
2510Sstevel@tonic-gate *
2520Sstevel@tonic-gate * .line num
2530Sstevel@tonic-gate *
2540Sstevel@tonic-gate * and similarly:
2550Sstevel@tonic-gate *
2560Sstevel@tonic-gate * # num "string" optional stuff
2570Sstevel@tonic-gate *
2580Sstevel@tonic-gate * is converted to
2590Sstevel@tonic-gate *
2600Sstevel@tonic-gate * .line num
2610Sstevel@tonic-gate * .file "string"
2620Sstevel@tonic-gate *
2630Sstevel@tonic-gate * While this could be done with a sequence of sed
2640Sstevel@tonic-gate * commands, this is simpler and faster..
2650Sstevel@tonic-gate */
2660Sstevel@tonic-gate static pid_t
filter(int pipein,int pipeout)2670Sstevel@tonic-gate filter(int pipein, int pipeout)
2680Sstevel@tonic-gate {
2690Sstevel@tonic-gate pid_t pid;
2700Sstevel@tonic-gate FILE *in, *out;
2717064Sab196087 char *wspace;
2727064Sab196087 size_t wspace_len;
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate if (verbose)
2750Sstevel@tonic-gate (void) fprintf(stderr, "{#line filter} ");
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate switch (pid = fork()) {
2780Sstevel@tonic-gate case 0:
2790Sstevel@tonic-gate if (dup2(pipein, 0) == -1 ||
2800Sstevel@tonic-gate dup2(pipeout, 1) == -1) {
2810Sstevel@tonic-gate perror("dup2");
2820Sstevel@tonic-gate exit(1);
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate closefrom(3);
2850Sstevel@tonic-gate break;
2860Sstevel@tonic-gate case -1:
2870Sstevel@tonic-gate perror("fork");
2880Sstevel@tonic-gate default:
2890Sstevel@tonic-gate return (pid);
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate in = fdopen(0, "r");
2930Sstevel@tonic-gate out = fdopen(1, "w");
2940Sstevel@tonic-gate
2957064Sab196087 /*
2967064Sab196087 * Key off the CODEMGR_WS environment variable to detect
2977064Sab196087 * if we're in an activated workspace, and to get the
2987064Sab196087 * path to the workspace.
2997064Sab196087 */
3007064Sab196087 wspace = getenv("CODEMGR_WS");
3017064Sab196087 if (wspace != NULL)
3027064Sab196087 wspace_len = strlen(wspace);
3037064Sab196087
3040Sstevel@tonic-gate while (!feof(in)) {
3050Sstevel@tonic-gate int c, num;
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate switch (c = fgetc(in)) {
3080Sstevel@tonic-gate case '#':
3090Sstevel@tonic-gate switch (fscanf(in, " %d", &num)) {
3100Sstevel@tonic-gate case 0:
3110Sstevel@tonic-gate /*
3120Sstevel@tonic-gate * discard comment lines completely
3130Sstevel@tonic-gate * discard ident strings completely too.
3140Sstevel@tonic-gate * (GNU as politely ignores them..)
3150Sstevel@tonic-gate */
3160Sstevel@tonic-gate copyuntil(in, NULL, '\n');
3170Sstevel@tonic-gate break;
3180Sstevel@tonic-gate default:
3190Sstevel@tonic-gate (void) fprintf(stderr, "fscanf botch?");
3200Sstevel@tonic-gate /*FALLTHROUGH*/
3210Sstevel@tonic-gate case EOF:
3220Sstevel@tonic-gate exit(1);
3230Sstevel@tonic-gate /*NOTREACHED*/
3240Sstevel@tonic-gate case 1:
3250Sstevel@tonic-gate /*
3260Sstevel@tonic-gate * This line has a number at the beginning;
3270Sstevel@tonic-gate * if it has a string after the number, then
3280Sstevel@tonic-gate * it's a filename.
3297064Sab196087 *
3307064Sab196087 * If this is an activated workspace, use
3317064Sab196087 * copyuntil_path() to do path rewriting
3327064Sab196087 * that will prevent workspace paths from
3337064Sab196087 * being burned into the resulting object.
3347064Sab196087 * If not in an activated workspace, then
3357064Sab196087 * copy the existing path straight through
3367064Sab196087 * without interpretation.
3370Sstevel@tonic-gate */
3380Sstevel@tonic-gate if (fgetc(in) == ' ' && fgetc(in) == '"') {
3390Sstevel@tonic-gate (void) fprintf(out, "\t.file \"");
3407064Sab196087 if (wspace != NULL)
3417064Sab196087 copyuntil_path(in, out, '"',
3427064Sab196087 wspace, wspace_len);
3437064Sab196087 else
3447064Sab196087 copyuntil(in, out, '"');
3450Sstevel@tonic-gate (void) fputc('\n', out);
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate (void) fprintf(out, "\t.line %d\n", num - 1);
3480Sstevel@tonic-gate /*
3490Sstevel@tonic-gate * discard the rest of the line
3500Sstevel@tonic-gate */
3510Sstevel@tonic-gate copyuntil(in, NULL, '\n');
3520Sstevel@tonic-gate break;
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate break;
3550Sstevel@tonic-gate case '\n':
3560Sstevel@tonic-gate /*
3570Sstevel@tonic-gate * preserve newlines
3580Sstevel@tonic-gate */
3590Sstevel@tonic-gate (void) fputc(c, out);
3600Sstevel@tonic-gate break;
3610Sstevel@tonic-gate case EOF:
3620Sstevel@tonic-gate /*
3630Sstevel@tonic-gate * don't write EOF!
3640Sstevel@tonic-gate */
3650Sstevel@tonic-gate break;
3660Sstevel@tonic-gate default:
3670Sstevel@tonic-gate /*
3680Sstevel@tonic-gate * lines that don't begin with '#' are copied
3690Sstevel@tonic-gate */
3700Sstevel@tonic-gate (void) fputc(c, out);
3710Sstevel@tonic-gate copyuntil(in, out, '\n');
3720Sstevel@tonic-gate break;
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate
3750Sstevel@tonic-gate if (ferror(out))
3760Sstevel@tonic-gate exit(1);
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate exit(0);
3800Sstevel@tonic-gate /*NOTREACHED*/
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate static pid_t
invoke(char ** argv,int pipein,int pipeout)3840Sstevel@tonic-gate invoke(char **argv, int pipein, int pipeout)
3850Sstevel@tonic-gate {
3860Sstevel@tonic-gate pid_t pid;
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate if (verbose) {
3890Sstevel@tonic-gate char **dargv = argv;
3900Sstevel@tonic-gate
3910Sstevel@tonic-gate while (*dargv)
3920Sstevel@tonic-gate (void) fprintf(stderr, "%s ", *dargv++);
3930Sstevel@tonic-gate }
3940Sstevel@tonic-gate
3950Sstevel@tonic-gate switch (pid = fork()) {
3960Sstevel@tonic-gate case 0:
3970Sstevel@tonic-gate if (pipein >= 0 && dup2(pipein, 0) == -1) {
3980Sstevel@tonic-gate perror("dup2");
3990Sstevel@tonic-gate exit(1);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate if (pipeout >= 0 && dup2(pipeout, 1) == -1) {
4020Sstevel@tonic-gate perror("dup2");
4030Sstevel@tonic-gate exit(1);
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate closefrom(3);
4060Sstevel@tonic-gate (void) execvp(argv[0], argv);
4070Sstevel@tonic-gate perror("execvp");
4080Sstevel@tonic-gate (void) fprintf(stderr, "%s: couldn't run %s\n",
4090Sstevel@tonic-gate progname, argv[0]);
4100Sstevel@tonic-gate break;
4110Sstevel@tonic-gate case -1:
4120Sstevel@tonic-gate perror("fork");
4130Sstevel@tonic-gate default:
4140Sstevel@tonic-gate return (pid);
4150Sstevel@tonic-gate }
4160Sstevel@tonic-gate exit(2);
4170Sstevel@tonic-gate /*NOTREACHED*/
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate
4200Sstevel@tonic-gate static int
pipeline(char ** ppargv,char ** asargv)4210Sstevel@tonic-gate pipeline(char **ppargv, char **asargv)
4220Sstevel@tonic-gate {
4230Sstevel@tonic-gate int pipedes[4];
4240Sstevel@tonic-gate int active = 0;
4250Sstevel@tonic-gate int rval = 0;
4260Sstevel@tonic-gate pid_t pid_pp, pid_f, pid_as;
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate if (pipe(pipedes) == -1 || pipe(pipedes + 2) == -1) {
4290Sstevel@tonic-gate perror("pipe");
4300Sstevel@tonic-gate return (4);
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate
4330Sstevel@tonic-gate if ((pid_pp = invoke(ppargv, -1, pipedes[0])) > 0)
4340Sstevel@tonic-gate active++;
4350Sstevel@tonic-gate
4360Sstevel@tonic-gate if (verbose)
4370Sstevel@tonic-gate (void) fprintf(stderr, "| ");
4380Sstevel@tonic-gate
4390Sstevel@tonic-gate if ((pid_f = filter(pipedes[1], pipedes[2])) > 0)
4400Sstevel@tonic-gate active++;
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate if (verbose)
4430Sstevel@tonic-gate (void) fprintf(stderr, "| ");
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate if ((pid_as = invoke(asargv, pipedes[3], -1)) > 0)
4460Sstevel@tonic-gate active++;
4470Sstevel@tonic-gate
4480Sstevel@tonic-gate if (verbose) {
4490Sstevel@tonic-gate (void) fprintf(stderr, "\n");
4500Sstevel@tonic-gate (void) fflush(stderr);
4510Sstevel@tonic-gate }
4520Sstevel@tonic-gate
4530Sstevel@tonic-gate closefrom(3);
4540Sstevel@tonic-gate
4550Sstevel@tonic-gate if (active != 3)
4560Sstevel@tonic-gate return (5);
4570Sstevel@tonic-gate
4580Sstevel@tonic-gate while (active != 0) {
4590Sstevel@tonic-gate pid_t pid;
4600Sstevel@tonic-gate int stat;
4610Sstevel@tonic-gate
4620Sstevel@tonic-gate if ((pid = wait(&stat)) == -1) {
4630Sstevel@tonic-gate rval++;
4640Sstevel@tonic-gate break;
4650Sstevel@tonic-gate }
4660Sstevel@tonic-gate
4670Sstevel@tonic-gate if (!WIFEXITED(stat))
4680Sstevel@tonic-gate continue;
4690Sstevel@tonic-gate
4700Sstevel@tonic-gate if (pid == pid_pp || pid == pid_f || pid == pid_as) {
4710Sstevel@tonic-gate active--;
4720Sstevel@tonic-gate if (WEXITSTATUS(stat) != 0)
4730Sstevel@tonic-gate rval++;
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate }
4760Sstevel@tonic-gate
4770Sstevel@tonic-gate return (rval);
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate
4800Sstevel@tonic-gate int
main(int argc,char * argv[])4810Sstevel@tonic-gate main(int argc, char *argv[])
4820Sstevel@tonic-gate {
4830Sstevel@tonic-gate struct aelist *cpp = NULL;
4840Sstevel@tonic-gate struct aelist *m4 = NULL;
4850Sstevel@tonic-gate struct aelist *as = newael();
4860Sstevel@tonic-gate char **asargv;
4870Sstevel@tonic-gate char *outfile = NULL;
4880Sstevel@tonic-gate char *srcfile = NULL;
489*11997SScott.Rotondo@Sun.COM const char *dir, *cmd;
490*11997SScott.Rotondo@Sun.COM static char as_pgm[MAXPATHLEN];
491*11997SScott.Rotondo@Sun.COM static char as64_pgm[MAXPATHLEN];
492*11997SScott.Rotondo@Sun.COM static char m4_pgm[MAXPATHLEN];
493*11997SScott.Rotondo@Sun.COM static char m4_cmdefs[MAXPATHLEN];
494*11997SScott.Rotondo@Sun.COM static char cpp_pgm[MAXPATHLEN];
4950Sstevel@tonic-gate int as64 = 0;
4960Sstevel@tonic-gate int code;
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate if ((progname = strrchr(argv[0], '/')) == NULL)
4990Sstevel@tonic-gate progname = argv[0];
5000Sstevel@tonic-gate else
5010Sstevel@tonic-gate progname++;
5020Sstevel@tonic-gate
5030Sstevel@tonic-gate /*
5040Sstevel@tonic-gate * Helpful when debugging, or when changing tool versions..
5050Sstevel@tonic-gate */
506*11997SScott.Rotondo@Sun.COM if ((cmd = getenv("AW_AS")) != NULL)
507*11997SScott.Rotondo@Sun.COM strlcpy(as_pgm, cmd, sizeof (as_pgm));
508*11997SScott.Rotondo@Sun.COM else {
509*11997SScott.Rotondo@Sun.COM if ((dir = getenv("AW_AS_DIR")) == NULL)
510*11997SScott.Rotondo@Sun.COM dir = DEFAULT_AS_DIR; /* /usr/sfw/bin */
511*11997SScott.Rotondo@Sun.COM (void) snprintf(as_pgm, sizeof (as_pgm), "%s/gas", dir);
512*11997SScott.Rotondo@Sun.COM }
5130Sstevel@tonic-gate
514*11997SScott.Rotondo@Sun.COM if ((cmd = getenv("AW_AS64")) != NULL)
515*11997SScott.Rotondo@Sun.COM strlcpy(as64_pgm, cmd, sizeof (as64_pgm));
516*11997SScott.Rotondo@Sun.COM else {
517*11997SScott.Rotondo@Sun.COM if ((dir = getenv("AW_AS64_DIR")) == NULL)
518*11997SScott.Rotondo@Sun.COM dir = DEFAULT_AS64_DIR; /* /usr/sfw/bin */
519*11997SScott.Rotondo@Sun.COM (void) snprintf(as64_pgm, sizeof (as_pgm), "%s/gas", dir);
520*11997SScott.Rotondo@Sun.COM }
5210Sstevel@tonic-gate
522*11997SScott.Rotondo@Sun.COM if ((cmd = getenv("AW_M4")) != NULL)
523*11997SScott.Rotondo@Sun.COM strlcpy(m4_pgm, cmd, sizeof (m4_pgm));
524*11997SScott.Rotondo@Sun.COM else {
525*11997SScott.Rotondo@Sun.COM if ((dir = getenv("AW_M4_DIR")) == NULL)
526*11997SScott.Rotondo@Sun.COM dir = DEFAULT_M4_DIR; /* /usr/ccs/bin */
527*11997SScott.Rotondo@Sun.COM (void) snprintf(m4_pgm, sizeof (m4_pgm), "%s/m4", dir);
528*11997SScott.Rotondo@Sun.COM }
5290Sstevel@tonic-gate
530*11997SScott.Rotondo@Sun.COM if ((cmd = getenv("AW_M4LIB")) != NULL)
531*11997SScott.Rotondo@Sun.COM strlcpy(m4_cmdefs, cmd, sizeof (m4_cmdefs));
532*11997SScott.Rotondo@Sun.COM else {
533*11997SScott.Rotondo@Sun.COM if ((dir = getenv("AW_M4LIB_DIR")) == NULL)
534*11997SScott.Rotondo@Sun.COM dir = DEFAULT_M4LIB_DIR; /* /usr/ccs/lib */
535*11997SScott.Rotondo@Sun.COM (void) snprintf(m4_cmdefs, sizeof (m4_cmdefs),
536*11997SScott.Rotondo@Sun.COM "%s/cm4defs", dir);
537*11997SScott.Rotondo@Sun.COM }
5380Sstevel@tonic-gate
539*11997SScott.Rotondo@Sun.COM if ((cmd = getenv("AW_CPP")) != NULL)
540*11997SScott.Rotondo@Sun.COM strlcpy(cpp_pgm, cmd, sizeof (cpp_pgm));
541*11997SScott.Rotondo@Sun.COM else {
542*11997SScott.Rotondo@Sun.COM if ((dir = getenv("AW_CPP_DIR")) == NULL)
543*11997SScott.Rotondo@Sun.COM dir = DEFAULT_CPP_DIR; /* /usr/ccs/lib */
544*11997SScott.Rotondo@Sun.COM (void) snprintf(cpp_pgm, sizeof (cpp_pgm), "%s/cpp", dir);
545*11997SScott.Rotondo@Sun.COM }
5460Sstevel@tonic-gate
5470Sstevel@tonic-gate newae(as, as_pgm);
5480Sstevel@tonic-gate newae(as, "--warn");
5490Sstevel@tonic-gate newae(as, "--fatal-warnings");
5500Sstevel@tonic-gate newae(as, "--traditional-format");
5510Sstevel@tonic-gate
5520Sstevel@tonic-gate /*
5530Sstevel@tonic-gate * This is a support hack to rewrite code for the compiler
5540Sstevel@tonic-gate * which should probably cause an assembler programmer to recode
5550Sstevel@tonic-gate * - so, generate a warning in this case.
5569291SGeorge.Vasick@Sun.COM *
5579291SGeorge.Vasick@Sun.COM * -K was dropped begining with version 2.18.
5580Sstevel@tonic-gate */
5599291SGeorge.Vasick@Sun.COM {
5609291SGeorge.Vasick@Sun.COM struct aelist *as_ver = newael();
5619291SGeorge.Vasick@Sun.COM struct aelist *ggrep = newael();
5629291SGeorge.Vasick@Sun.COM
5639291SGeorge.Vasick@Sun.COM newae(as_ver, as_pgm);
5649291SGeorge.Vasick@Sun.COM newae(as_ver, "--version");
5659291SGeorge.Vasick@Sun.COM newae(ggrep, "/usr/bin/ggrep");
5669291SGeorge.Vasick@Sun.COM newae(ggrep, "-q");
5679291SGeorge.Vasick@Sun.COM newae(ggrep, "-E");
5689291SGeorge.Vasick@Sun.COM newae(ggrep, "2.1[567]");
5699291SGeorge.Vasick@Sun.COM code = pipeline(aeltoargv(as_ver), aeltoargv(ggrep));
5709291SGeorge.Vasick@Sun.COM if (code == 0) {
5719291SGeorge.Vasick@Sun.COM newae(as, "-K");
5729291SGeorge.Vasick@Sun.COM }
5739291SGeorge.Vasick@Sun.COM }
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate /*
5760Sstevel@tonic-gate * Walk the argument list, translating as we go ..
5770Sstevel@tonic-gate */
5780Sstevel@tonic-gate while (--argc > 0) {
5790Sstevel@tonic-gate char *arg;
5800Sstevel@tonic-gate int arglen;
5810Sstevel@tonic-gate
5820Sstevel@tonic-gate arg = *++argv;
5830Sstevel@tonic-gate arglen = strlen(arg);
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate if (*arg != '-') {
5860Sstevel@tonic-gate char *filename;
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate /*
5890Sstevel@tonic-gate * filenames ending in '.s' are taken to be
5900Sstevel@tonic-gate * assembler files, and provide the default
5910Sstevel@tonic-gate * basename of the output file.
5920Sstevel@tonic-gate *
5930Sstevel@tonic-gate * other files are passed through to the
5940Sstevel@tonic-gate * preprocessor, if present, or to gas if not.
5950Sstevel@tonic-gate */
5960Sstevel@tonic-gate filename = arg;
5970Sstevel@tonic-gate if (arglen > 2 &&
5980Sstevel@tonic-gate strcmp(arg + arglen - 2, ".s") == 0) {
5990Sstevel@tonic-gate /*
6000Sstevel@tonic-gate * Though 'as' allows multiple assembler
6010Sstevel@tonic-gate * files to be processed in one invocation
6020Sstevel@tonic-gate * of the assembler, ON only processes one
6030Sstevel@tonic-gate * file at a time, which makes things a lot
6040Sstevel@tonic-gate * simpler!
6050Sstevel@tonic-gate */
6060Sstevel@tonic-gate if (srcfile == NULL)
6070Sstevel@tonic-gate srcfile = arg;
6080Sstevel@tonic-gate else
6090Sstevel@tonic-gate return (usage(
6100Sstevel@tonic-gate "one assembler file at a time"));
6110Sstevel@tonic-gate
6120Sstevel@tonic-gate /*
6130Sstevel@tonic-gate * If we haven't seen a -o option yet,
6140Sstevel@tonic-gate * default the output to the basename
6150Sstevel@tonic-gate * of the input, substituting a .o on the end
6160Sstevel@tonic-gate */
6170Sstevel@tonic-gate if (outfile == NULL) {
6180Sstevel@tonic-gate char *argcopy;
6190Sstevel@tonic-gate
6200Sstevel@tonic-gate argcopy = strdup(arg);
6210Sstevel@tonic-gate argcopy[arglen - 1] = 'o';
6220Sstevel@tonic-gate
6230Sstevel@tonic-gate if ((outfile = strrchr(
6240Sstevel@tonic-gate argcopy, '/')) == NULL)
6250Sstevel@tonic-gate outfile = argcopy;
6260Sstevel@tonic-gate else
6270Sstevel@tonic-gate outfile++;
6280Sstevel@tonic-gate }
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate if (cpp)
6310Sstevel@tonic-gate newae(cpp, filename);
6320Sstevel@tonic-gate else if (m4)
6330Sstevel@tonic-gate newae(m4, filename);
6340Sstevel@tonic-gate else
6350Sstevel@tonic-gate newae(as, filename);
6360Sstevel@tonic-gate continue;
6370Sstevel@tonic-gate } else
6380Sstevel@tonic-gate arglen--;
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate switch (arg[1]) {
6410Sstevel@tonic-gate case 'K':
6420Sstevel@tonic-gate /*
6430Sstevel@tonic-gate * -K pic
6440Sstevel@tonic-gate * -K PIC
6450Sstevel@tonic-gate */
6460Sstevel@tonic-gate if (arglen == 1) {
6470Sstevel@tonic-gate if ((arg = *++argv) == NULL || *arg == '\0')
6480Sstevel@tonic-gate return (usage("malformed -K"));
6490Sstevel@tonic-gate argc--;
6500Sstevel@tonic-gate } else {
6510Sstevel@tonic-gate arg += 2;
6520Sstevel@tonic-gate }
6530Sstevel@tonic-gate if (strcmp(arg, "PIC") != 0 && strcmp(arg, "pic") != 0)
6540Sstevel@tonic-gate return (usage("malformed -K"));
6550Sstevel@tonic-gate break; /* just ignore -Kpic for gcc */
6560Sstevel@tonic-gate case 'Q':
6570Sstevel@tonic-gate if (strcmp(arg, "-Qn") == 0)
6580Sstevel@tonic-gate break;
6590Sstevel@tonic-gate /*FALLTHROUGH*/
6600Sstevel@tonic-gate case 'b':
6610Sstevel@tonic-gate case 's':
6620Sstevel@tonic-gate case 'T':
6630Sstevel@tonic-gate /*
6640Sstevel@tonic-gate * -b Extra symbol table for source browser ..
6650Sstevel@tonic-gate * not relevant to gas, thus should error.
6660Sstevel@tonic-gate * -s Put stabs in .stabs section not stabs.excl
6670Sstevel@tonic-gate * not clear if there's an equivalent
6680Sstevel@tonic-gate * -T 4.x migration option
6690Sstevel@tonic-gate */
6700Sstevel@tonic-gate default:
6710Sstevel@tonic-gate return (error(arg));
6720Sstevel@tonic-gate case 'x':
6730Sstevel@tonic-gate /*
6740Sstevel@tonic-gate * Accept -xarch special case to invoke alternate
6750Sstevel@tonic-gate * assemblers or assembler flags for different
6760Sstevel@tonic-gate * architectures.
6770Sstevel@tonic-gate */
6780Sstevel@tonic-gate if (strcmp(arg, "-xarch=amd64") == 0 ||
6790Sstevel@tonic-gate strcmp(arg, "-xarch=generic64") == 0) {
6800Sstevel@tonic-gate as64++;
6810Sstevel@tonic-gate fixae_arg(as->ael_head, as64_pgm);
6820Sstevel@tonic-gate break;
6830Sstevel@tonic-gate }
6840Sstevel@tonic-gate /*
6850Sstevel@tonic-gate * XX64: Is this useful to gas?
6860Sstevel@tonic-gate */
6870Sstevel@tonic-gate if (strcmp(arg, "-xmodel=kernel") == 0)
6880Sstevel@tonic-gate break;
6890Sstevel@tonic-gate
6900Sstevel@tonic-gate /*
6910Sstevel@tonic-gate * -xF Generates performance analysis data
6920Sstevel@tonic-gate * no equivalent
6930Sstevel@tonic-gate */
6940Sstevel@tonic-gate return (error(arg));
6950Sstevel@tonic-gate case 'V':
6960Sstevel@tonic-gate newae(as, arg);
6970Sstevel@tonic-gate break;
6980Sstevel@tonic-gate case '#':
6990Sstevel@tonic-gate verbose++;
7000Sstevel@tonic-gate break;
7010Sstevel@tonic-gate case 'L':
7020Sstevel@tonic-gate newae(as, "--keep-locals");
7030Sstevel@tonic-gate break;
7040Sstevel@tonic-gate case 'n':
7050Sstevel@tonic-gate newae(as, "--no-warn");
7060Sstevel@tonic-gate break;
7070Sstevel@tonic-gate case 'o':
7080Sstevel@tonic-gate if (arglen != 1)
7090Sstevel@tonic-gate return (usage("bad -o flag"));
7100Sstevel@tonic-gate if ((arg = *++argv) == NULL || *arg == '\0')
7110Sstevel@tonic-gate return (usage("bad -o flag"));
7120Sstevel@tonic-gate outfile = arg;
7130Sstevel@tonic-gate argc--;
7140Sstevel@tonic-gate arglen = strlen(arg + 1);
7150Sstevel@tonic-gate break;
7160Sstevel@tonic-gate case 'm':
7170Sstevel@tonic-gate if (cpp)
7180Sstevel@tonic-gate return (usage("-m conflicts with -P"));
7190Sstevel@tonic-gate if (m4 == NULL) {
7200Sstevel@tonic-gate m4 = newael();
7210Sstevel@tonic-gate newae(m4, m4_pgm);
7220Sstevel@tonic-gate newae(m4, m4_cmdefs);
7230Sstevel@tonic-gate }
7240Sstevel@tonic-gate break;
7250Sstevel@tonic-gate case 'P':
7260Sstevel@tonic-gate if (m4)
7270Sstevel@tonic-gate return (usage("-P conflicts with -m"));
7280Sstevel@tonic-gate if (cpp == NULL) {
7290Sstevel@tonic-gate cpp = newael();
7300Sstevel@tonic-gate newae(cpp, cpp_pgm);
7310Sstevel@tonic-gate newae(cpp, "-D__GNUC_AS__");
7320Sstevel@tonic-gate }
7330Sstevel@tonic-gate break;
7340Sstevel@tonic-gate case 'D':
7350Sstevel@tonic-gate case 'U':
7360Sstevel@tonic-gate if (cpp)
7370Sstevel@tonic-gate newae(cpp, arg);
7380Sstevel@tonic-gate else if (m4)
7390Sstevel@tonic-gate newae(m4, arg);
7400Sstevel@tonic-gate else
7410Sstevel@tonic-gate newae(as, arg);
7420Sstevel@tonic-gate break;
7430Sstevel@tonic-gate case 'I':
7440Sstevel@tonic-gate if (cpp)
7450Sstevel@tonic-gate newae(cpp, arg);
7460Sstevel@tonic-gate else
7470Sstevel@tonic-gate newae(as, arg);
7480Sstevel@tonic-gate break;
7490Sstevel@tonic-gate case '-': /* a gas-specific option */
7500Sstevel@tonic-gate newae(as, arg);
7510Sstevel@tonic-gate break;
7520Sstevel@tonic-gate }
7530Sstevel@tonic-gate }
7540Sstevel@tonic-gate
7550Sstevel@tonic-gate #if defined(__i386)
7560Sstevel@tonic-gate if (as64)
7570Sstevel@tonic-gate newae(as, "--64");
7580Sstevel@tonic-gate else
7590Sstevel@tonic-gate newae(as, "--32");
7600Sstevel@tonic-gate #endif
7610Sstevel@tonic-gate
7620Sstevel@tonic-gate if (srcfile == NULL)
7630Sstevel@tonic-gate return (usage("no source file(s) specified"));
7640Sstevel@tonic-gate if (outfile == NULL)
7650Sstevel@tonic-gate outfile = "a.out";
7660Sstevel@tonic-gate newae(as, "-o");
7670Sstevel@tonic-gate newae(as, outfile);
7680Sstevel@tonic-gate
7690Sstevel@tonic-gate asargv = aeltoargv(as);
7700Sstevel@tonic-gate if (cpp) {
7710Sstevel@tonic-gate #if defined(__sparc)
7720Sstevel@tonic-gate newae(cpp, "-Dsparc");
7730Sstevel@tonic-gate newae(cpp, "-D__sparc");
7740Sstevel@tonic-gate if (as64)
7750Sstevel@tonic-gate newae(cpp, "-D__sparcv9");
7760Sstevel@tonic-gate else
7770Sstevel@tonic-gate newae(cpp, "-D__sparcv8");
7780Sstevel@tonic-gate #elif defined(__i386) || defined(__x86)
7790Sstevel@tonic-gate if (as64) {
7800Sstevel@tonic-gate newae(cpp, "-D__x86_64");
7810Sstevel@tonic-gate newae(cpp, "-D__amd64");
7820Sstevel@tonic-gate } else {
7830Sstevel@tonic-gate newae(cpp, "-Di386");
7840Sstevel@tonic-gate newae(cpp, "-D__i386");
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate #else
7870Sstevel@tonic-gate #error "need isa-dependent defines"
7880Sstevel@tonic-gate #endif
7890Sstevel@tonic-gate code = pipeline(aeltoargv(cpp), asargv);
7900Sstevel@tonic-gate } else if (m4)
7910Sstevel@tonic-gate code = pipeline(aeltoargv(m4), asargv);
7920Sstevel@tonic-gate else {
7930Sstevel@tonic-gate /*
7940Sstevel@tonic-gate * XXX should arrange to fork/exec so that we
7950Sstevel@tonic-gate * can unlink the output file if errors are
7960Sstevel@tonic-gate * detected..
7970Sstevel@tonic-gate */
7980Sstevel@tonic-gate (void) execvp(asargv[0], asargv);
7990Sstevel@tonic-gate perror("execvp");
8000Sstevel@tonic-gate (void) fprintf(stderr, "%s: couldn't run %s\n",
8010Sstevel@tonic-gate progname, asargv[0]);
8020Sstevel@tonic-gate code = 7;
8030Sstevel@tonic-gate }
8040Sstevel@tonic-gate if (code != 0)
8050Sstevel@tonic-gate (void) unlink(outfile);
8060Sstevel@tonic-gate return (code);
8070Sstevel@tonic-gate }
808