|
|
1.1 root 1: /*
2: * Copyright (c) 1982 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char copyright[] =
9: "@(#) Copyright (c) 1982 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)asmain.c 5.6 (Berkeley) 6/30/90";
15: #endif not lint
16:
17: #include <stdio.h>
18: #include <ctype.h>
19: #include <signal.h>
20:
21: #include "as.h"
22: #include "assyms.h"
23: #include "asscan.h"
24: #include "asexpr.h"
25: #include <paths.h>
26:
27: #include <sys/stat.h>
28:
29: #define unix_lang_name "VAX/UNIX Assembler V6/30/90 5.6"
30: /*
31: * variables to manage reading the assembly source files
32: */
33: char *dotsname; /*the current file name; managed by the parser*/
34: int lineno; /*current line number; managed by the parser*/
35: char **innames; /*names of the files being assembled*/
36: int ninfiles; /*how many interesting files there are*/
37: /*
38: * Flags settable from the argv process argument list
39: */
40: int silent = 0; /*don't complain about any errors*/
41: int savelabels = 0; /*write the labels to the a.out file*/
42: int d124 = 4; /*default allocate 4 bytes for unknown pointers*/
43: int maxalign = 2; /*default .align maximum*/
44: int anyerrs = 0; /*no errors yet*/
45: int anywarnings=0; /*no warnings yet*/
46: int orgwarn = 0; /*Bad origins*/
47: int passno = 1; /* current pass*/
48: int jxxxJUMP = 0; /* in jxxxes that branch too far, use jmp instead of brw */
49: int readonlydata = 0; /* initialzed data -> text space */
50:
51: int nGHnumbers = 0; /* GH numbers used */
52: int nGHopcodes = 0; /* GH opcodes used */
53: int nnewopcodes = 0; /* new opcodes used */
54:
55: #ifdef DEBUG
56: int debug = 0;
57: int toktrace = 0;
58: #endif
59:
60: int useVM = 0;
61:
62: char *endcore; /*where to get more symbol space*/
63:
64: /*
65: * Managers of the a.out file.
66: */
67: struct exec hdr;
68: #define MAGIC 0407
69: u_long tsize; /* total text size */
70: u_long dsize; /* total data size */
71: u_long datbase; /* base of the data segment */
72: u_long trsize; /* total text relocation size */
73: u_long drsize; /* total data relocation size */
74:
75: /*
76: * Information about the current segment is accumulated in
77: * usedot; the most important information stored is the
78: * accumulated size of each of the text and data segments
79: *
80: * dotp points to the correct usedot expression for the current segment
81: */
82: struct exp usedot[NLOC+NLOC]; /* info about all segments */
83: struct exp *dotp; /* data/text location pointer */
84: /*
85: * The inter pass temporary token file is opened and closed by stdio, but
86: * is written to using direct read/write, as the temporary file
87: * is composed of buffers exactly BUFSIZ long.
88: */
89: FILE *tokfile; /* interpass communication file */
90: char tokfilename[TNAMESIZE];
91: /*
92: * The string file is the string table
93: * cat'ed to the end of the built up a.out file
94: */
95: FILE *strfile; /* interpass string file */
96: char strfilename[TNAMESIZE];
97: int strfilepos = 0; /* position within the string file */
98: /*
99: * a.out is created during the second pass.
100: * It is opened by stdio, but is filled with the parallel
101: * block I/O library
102: */
103: char *outfile = "a.out";
104: FILE *a_out_file;
105: off_t a_out_off; /* cumulative offsets for segments */
106: /*
107: * The logical files containing the assembled data for each of
108: * the text and data segments are
109: * managed by the parallel block I/O library.
110: * a.out is logically opened in many places at once to
111: * receive the assembled data from the various segments as
112: * it all trickles in, but is physically opened only once
113: * to minimize file overhead.
114: */
115: BFILE *usefile[NLOC+NLOC]; /* text/data files */
116: BFILE *txtfil; /* current text/data file */
117: /*
118: * Relocation information is accumulated seperately for each
119: * segment. This is required by the old loader (from BTL),
120: * but not by the new loader (Bill Joy).
121: *
122: * However, the size of the relocation information can not be computed
123: * during or after the 1st pass because the ''absoluteness' of values
124: * is unknown until all locally declared symbols have been seen.
125: * Thus, the size of the relocation information is only
126: * known after the second pass is finished.
127: * This obviates the use of the block I/O
128: * library, which requires knowing the exact offsets in a.out.
129: *
130: * So, we save the relocation information internally (we don't
131: * go to internal files to minimize overhead).
132: *
133: * Empirically, we studied 259 files composing the system,
134: * two compilers and a compiler generator: (all of which have
135: * fairly large source files)
136: *
137: * Number of files = 259
138: * Number of non zero text reloc files: 233
139: * Number of non zero data reloc files: 53
140: * Average text relocation = 889
141: * Average data relocation = 346
142: * Number of files > BUFSIZ text relocation = 71
143: * Number of files > BUFSIZ data relocation = 6
144: *
145: * For compiled C code, there is usually one text segment and two
146: * data segments; we see that allocating our own buffers and
147: * doing our internal handling of relocation information will,
148: * on the average, not use more memory than taken up by the buffers
149: * allocated for doing file I/O in parallel to a number of file.
150: *
151: * If we are assembling with the -V option, we
152: * use the left over token buffers from the 2nd pass,
153: * otherwise, we create our own.
154: *
155: * When the 2nd pass is complete, closeoutrel flushes the token
156: * buffers out to a BFILE.
157: *
158: * The internals to relbufdesc are known only in assyms.c
159: *
160: * outrel constructs the relocation information.
161: * closeoutrel flushes the relocation information to relfil.
162: */
163: struct relbufdesc *rusefile[NLOC+NLOC];
164: struct relbufdesc *relfil; /* un concatnated relocation info */
165: BFILE *relocfile; /* concatnated relocation info */
166: /*
167: * Once the relocation information has been written,
168: * we can write out the symbol table using the Block I/O
169: * mechanisms, as we once again know the offsets into
170: * the a.out file.
171: *
172: * We use relfil to output the symbol table information.
173: */
174: char *tmpdirprefix = "/tmp/";
175: int delexit();
176:
177: main(argc, argv)
178: int argc;
179: char **argv;
180: {
181: char *sbrk();
182:
183: tokfilename[0] = 0;
184: strfilename[0] = 0;
185: endcore = sbrk(0);
186:
187: argprocess(argc, argv); /* process argument lists */
188: if (anyerrs) exit(1);
189:
190: initialize();
191: zeroorigins(); /* set origins to zero */
192: zerolocals(); /* fix local label counters */
193:
194: i_pass1(); /* open temp files, etc */
195: pass1(); /* first pass through .s files */
196: testlocals(); /* check for undefined locals */
197: if (anyerrs) delexit();
198:
199: pass1_5(); /* resolve jxxx */
200: if (anyerrs) delexit();
201:
202: open_a_out(); /* open a.out */
203: roundsegments(); /* round segments to FW */
204: build_hdr(); /* build initial header, and output */
205:
206: i_pass2(); /* reopen temporary file, etc */
207: pass2(); /* second pass through the virtual .s */
208: if (anyerrs) delexit();
209:
210: fillsegments(); /* fill segments with 0 to FW */
211: reloc_syms(); /* dump relocation and symbol table */
212:
213: delete(); /* remove tmp file */
214: bflush(); /* close off block I/O view of a.out */
215: fix_a_out(); /* add in text and data reloc counts */
216:
217: if (anyerrs == 0 && orgwarn)
218: yyerror("Caution: absolute origins.\n");
219:
220: if (nGHnumbers)
221: yywarning("Caution: G or H format floating point numbers");
222: if (nGHopcodes)
223: yywarning("Caution: G or H format floating point operators");
224: if (nnewopcodes)
225: yywarning("Caution: New Opcodes");
226: if (nGHnumbers || nGHopcodes || nnewopcodes)
227: yywarning("These are not defined for all implementations of the VAX architecture.\n");
228:
229: exit(anyerrs != 0);
230: }
231:
232: argprocess(argc, argv)
233: int argc;
234: char *argv[];
235: {
236: register char *cp;
237:
238: ninfiles = 0;
239: silent = 0;
240: #ifdef DEBUG
241: debug = 0;
242: #endif
243: innames = (char **)ClearCalloc(argc+1, sizeof (innames[0]));
244: dotsname = "<argv error>";
245: while (argc > 1) {
246: if (argv[1][0] != '-')
247: innames[ninfiles++] = argv[1];
248: else {
249: cp = argv[1] + 1;
250: /*
251: * We can throw away single minus signs, so
252: * that make scripts for the PDP 11 assembler work
253: * on this assembler too
254: */
255: while (*cp){
256: switch(*cp++){
257: default:
258: yyerror("Unknown flag: %c", *--cp);
259: cp++;
260: break;
261: case 'v':
262: selfwhat(stdout);
263: exit(1);
264: case 'd':
265: d124 = *cp++ - '0';
266: if ( (d124 != 1) && (d124 != 2) &&
267: (d124 != 4)){
268: yyerror("-d[124] only");
269: exit(1);
270: }
271: break;
272: case 'a':
273: maxalign = atoi(cp+1);
274: for (cp++; isdigit(*cp); cp++)
275: /*VOID*/;
276: if ( (maxalign > 16) || (maxalign < 0)){
277: yyerror("-a: 0<=align<=16");
278: exit(1);
279: }
280: break;
281: case 'o':
282: if (argc < 3){
283: yyerror("-o what???");
284: exit(1);
285: }
286: outfile = argv[2];
287: bumpone:
288: argc -= 2;
289: argv += 2;
290: goto nextarg;
291:
292: case 't':
293: if (argc < 3){
294: yyerror("-t what???");
295: exit(1);
296: }
297: tmpdirprefix = argv[2];
298: goto bumpone;
299:
300: case 'V':
301: useVM = 1;
302: break;
303: case 'W':
304: silent = 1;
305: break;
306: case 'L':
307: savelabels = 1;
308: break;
309: case 'J':
310: jxxxJUMP = 1;
311: break;
312: #ifdef DEBUG
313: case 'D':
314: debug = 1;
315: break;
316: case 'T':
317: toktrace = 1;
318: break;
319: #endif
320: case 'R':
321: readonlydata = 1;
322: break;
323: } /*end of the switch*/
324: } /*end of pulling out all arguments*/
325: } /*end of a flag argument*/
326: --argc; ++argv;
327: nextarg:;
328: }
329: /* innames[ninfiles] = 0; */
330: }
331: /*
332: * poke through the data space and find all sccs identifiers.
333: * We assume:
334: * a) that extern char **environ; is the first thing in the bss
335: * segment (true, if one is using the new version of cmgt.crt0.c)
336: * b) that the sccsid's have not been put into text space.
337: */
338: selfwhat(place)
339: FILE *place;
340: {
341: extern char **environ;
342: register char *ub;
343: register char *cp;
344: register char *pat;
345: char *sbrk();
346:
347: for (cp = (char *)&environ, ub = sbrk(0); cp < ub; cp++){
348: if (cp[0] != '@') continue;
349: if (cp[1] != '(') continue;
350: if (cp[2] != '#') continue;
351: if (cp[3] != ')') continue;
352: fputc('\t', place);
353: for (cp += 4; cp < ub; cp++){
354: if (*cp == 0) break;
355: if (*cp == '>') break;
356: if (*cp == '\n') break;
357: fputc(*cp, place);
358: }
359: fputc('\n', place);
360: }
361: }
362:
363: initialize()
364: {
365: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
366: signal(SIGINT, delexit);
367: /*
368: * Install symbols in the table
369: */
370: symtabinit();
371: syminstall();
372: /*
373: * Build the expression parser accelerator token sets
374: */
375: buildtokensets();
376: }
377:
378: zeroorigins()
379: {
380: register int locindex;
381: /*
382: * Mark usedot: the first NLOC slots are for named text segments,
383: * the next for named data segments.
384: */
385: for (locindex = 0; locindex < NLOC; locindex++){
386: usedot[locindex].e_xtype = XTEXT;
387: usedot[NLOC + locindex].e_xtype = XDATA;
388: usedot[locindex].e_xvalue = 0;
389: usedot[NLOC + locindex].e_xvalue = 0;
390: }
391: }
392:
393: zerolocals()
394: {
395: register int i;
396:
397: for (i = 0; i <= 9; i++) {
398: lgensym[i] = 1;
399: genref[i] = 0;
400: }
401: }
402:
403: i_pass1()
404: {
405: FILE *tempopen();
406: if (useVM == 0)
407: tokfile = tempopen(tokfilename, "T");
408: strfile = tempopen(strfilename, "S");
409: /*
410: * write out the string length.
411: * This will be overwritten when the
412: * strings are tacked onto the growing a.out file
413: */
414: strfilepos = sizeof(int);
415: fwrite(&strfilepos, sizeof(int), 1, strfile);
416:
417: inittokfile();
418: initijxxx();
419: }
420:
421: FILE *tempopen(tname, part)
422: char *tname;
423: char *part;
424: {
425: FILE *file;
426: (void)sprintf(tname, "%s%sas%s%05d",
427: tmpdirprefix,
428: (tmpdirprefix[strlen(tmpdirprefix)-1] != '/') ? "/" : "",
429: part,
430: getpid());
431: file = fopen(tname, "w");
432: if (file == NULL) {
433: yyerror("Bad pass 1 temporary file for writing %s", tname);
434: delexit();
435: }
436: return(file);
437: }
438:
439: pass1()
440: {
441: register int i;
442:
443: passno = 1;
444: dotp = &usedot[0];
445: txtfil = (BFILE *)0;
446: relfil = (struct relbufdesc *)0;
447:
448: if (ninfiles == 0){ /*take the input from stdin directly*/
449: lineno = 1;
450: dotsname = "<stdin>";
451:
452: yyparse();
453: } else { /*we have the names tanked*/
454: for (i = 0; i < ninfiles; i++){
455: new_dot_s(innames[i]);
456: if (freopen(innames[i], "r", stdin) == NULL) {
457: yyerror( "Can't open source file %s\n",
458: innames[i]);
459: exit(2);
460: }
461: /* stdio is NOT used to read the input characters */
462: /* we use read directly, into our own buffers */
463: yyparse();
464: }
465: }
466:
467: closetokfile(); /*kick out the last buffered intermediate text*/
468: }
469:
470: testlocals()
471: {
472: register int i;
473: for (i = 0; i <= 9; i++) {
474: if (genref[i])
475: yyerror("Reference to undefined local label %df", i);
476: lgensym[i] = 1;
477: genref[i] = 0;
478: }
479: }
480:
481: pass1_5()
482: {
483: sortsymtab();
484: #ifdef DEBUG
485: if (debug) dumpsymtab();
486: #endif
487: jxxxfix();
488: #ifdef DEBUG
489: if (debug) dumpsymtab();
490: #endif
491: }
492:
493: open_a_out()
494: {
495: struct stat stb;
496:
497: /*
498: * Open up the a.out file now, and get set to build
499: * up offsets into it for all of the various text,data
500: * text relocation and data relocation segments.
501: */
502: a_out_file = fopen(outfile, "w");
503: if (a_out_file == NULL) {
504: yyerror("Cannot create %s", outfile);
505: delexit();
506: }
507: biofd = a_out_file->_file;
508: fstat(biofd, &stb);
509: biobufsize = stb.st_blksize;
510: a_out_off = 0;
511: }
512:
513: roundsegments()
514: {
515: register int locindex;
516: register long v;
517: /*
518: * round and assign text segment origins
519: * the exec header always goes in usefile[0]
520: */
521: tsize = 0;
522: for (locindex=0; locindex<NLOC; locindex++) {
523: v = round(usedot[locindex].e_xvalue, FW);
524: usedot[locindex].e_xvalue = tsize;
525: if ((locindex == 0) || (v != 0) ){
526: usefile[locindex] = (BFILE *)Calloc(1, sizeof(BFILE));
527: bopen(usefile[locindex], a_out_off);
528: if (locindex == 0)
529: a_out_off = sizeof (struct exec);
530: } else {
531: usefile[locindex] = (BFILE *)-1;
532: }
533: tsize += v;
534: a_out_off += v;
535: }
536: /*
537: * Round and assign data segment origins.
538: */
539: datbase = round(tsize, FW);
540: for (locindex=0; locindex<NLOC; locindex++) {
541: v = round(usedot[NLOC+locindex].e_xvalue, FW);
542: usedot[NLOC+locindex].e_xvalue = datbase + dsize;
543: if (v != 0){
544: usefile[NLOC + locindex] = (BFILE *)Calloc(1,sizeof(BFILE));
545: bopen(usefile[NLOC + locindex], a_out_off);
546: } else {
547: usefile[NLOC + locindex] = (BFILE *)-1;
548: }
549: dsize += v;
550: a_out_off += v;
551: }
552: /*
553: * Assign final values to symbols
554: */
555: hdr.a_bss = dsize;
556: freezesymtab(); /* this touches hdr.a_bss */
557: stabfix();
558: /*
559: * Set up the relocation information "files" to
560: * be zero; outrel takes care of the rest
561: */
562: for (locindex = 0; locindex < NLOC + NLOC; locindex++){
563: rusefile[locindex] = (struct relbufdesc *)0;
564: }
565: }
566:
567: build_hdr()
568: {
569: /*
570: * Except for the text and data relocation sizes,
571: * calculate the final values for the header
572: *
573: * Write out the initial copy; we to come
574: * back later and patch up a_trsize and a_drsize,
575: * and overwrite this first version of the header.
576: */
577: hdr.a_magic = MAGIC;
578: hdr.a_text = tsize;
579: hdr.a_data = dsize;
580: hdr.a_bss -= dsize;
581: hdr.a_syms = sizesymtab(); /* Does not include string pool length */
582: hdr.a_entry = 0;
583: hdr.a_trsize = 0;
584: hdr.a_drsize = 0;
585:
586: bwrite((char *)&hdr, sizeof(hdr), usefile[0]);
587: }
588:
589: i_pass2()
590: {
591: if (useVM == 0) {
592: fclose(tokfile);
593: tokfile = fopen(tokfilename, "r");
594: if (tokfile==NULL) {
595: yyerror("Bad pass 2 temporary file for reading %s", tokfilename);
596: delexit();
597: }
598: }
599: fclose(strfile);
600: strfile = fopen(strfilename, "r");
601: }
602:
603: pass2()
604: {
605: #ifdef DEBUG
606: if (debug)
607: printf("\n\n\n\t\tPASS 2\n\n\n\n");
608: #endif DEBUG
609: passno = 2;
610: lineno = 1;
611: dotp = &usedot[0];
612: txtfil = usefile[0]; /* already opened (always!) */
613: relfil = 0; /* outrel takes care of the rest */
614: initoutrel();
615:
616: inittokfile();
617:
618: yyparse();
619:
620: closetokfile();
621: }
622:
623: fillsegments()
624: {
625: int locindex;
626: /*
627: * Round text and data segments to FW by appending zeros
628: */
629: for (locindex = 0; locindex < NLOC + NLOC; locindex++) {
630: if (usefile[locindex]) {
631: txtfil = usefile[locindex];
632: dotp = &usedot[locindex];
633: while (usedot[locindex].e_xvalue & FW)
634: outb(0);
635: }
636: }
637: }
638:
639: reloc_syms()
640: {
641: u_long closerelfil();
642: /*
643: * Move the relocation information to a.out
644: * a_out_off is the offset so far:
645: * exec + text segments + data segments
646: */
647: relocfile = (BFILE *)Calloc(1,sizeof(BFILE));
648: bopen(relocfile, a_out_off);
649: a_out_off += closeoutrel(relocfile);
650:
651: hdr.a_trsize = trsize;
652: hdr.a_drsize = drsize;
653: if (readonlydata) {
654: hdr.a_text += hdr.a_data;
655: hdr.a_data = 0;
656: hdr.a_trsize += hdr.a_drsize;
657: hdr.a_drsize = 0;
658: }
659: /*
660: * Output the symbol table and the string pool
661: *
662: * We must first rewind the string pool file to its beginning,
663: * in case it was seek'ed into for fetching ascii and asciz
664: * strings.
665: */
666: fseek(strfile, 0, 0);
667: symwrite(relocfile);
668: }
669:
670: fix_a_out()
671: {
672: if (lseek(a_out_file->_file, 0L, 0) < 0L)
673: yyerror("Reposition for header rewrite fails");
674: if (write(a_out_file->_file, (char *)&hdr, sizeof (struct exec)) < 0)
675: yyerror("Rewrite of header fails");
676: }
677:
678: delexit()
679: {
680: delete();
681: if (passno == 2){
682: unlink(outfile);
683: }
684: exit(1);
685: }
686:
687: delete()
688: {
689: if (useVM == 0 || tokfilename[0])
690: unlink(tokfilename);
691: if (strfilename[0])
692: unlink(strfilename);
693: }
694:
695: sawabort()
696: {
697: char *fillinbuffer();
698: while (fillinbuffer() != (char *)0)
699: continue;
700: delete();
701: exit(1); /*although the previous pass will also exit non zero*/
702: }
703:
704: panic(fmt, a1, a2, a3, a4)
705: char *fmt;
706: /*VARARGS 1*/
707: {
708: yyerror("Assembler panic: bad internal data structure.");
709: yyerror(fmt, a1, a2, a3, a4);
710: delete();
711: abort();
712: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.