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