date and time created 80/08/13 18:55:27 by bill
[unix-history] / usr / src / old / as.vax / asmain.c
CommitLineData
59e14996
BJ
1/* Copyright (c) 1980 Regents of the University of California */
2static char sccsid[] = "@(#)asmain.c 4.1 %G%";
3#include <stdio.h>
4#include <ctype.h>
5#include <sys/types.h>
6#include <signal.h>
7#include <a.out.h>
8
9#include "as.h"
10#include "assyms.h"
11#include "asexpr.h"
12#include "asscan.h"
13
14#ifdef UNIX
15#define unix_lang_name "VAX/UNIX Assembler V3.0"
16#endif
17
18#ifdef VMS
19#define vms_lang_name "VAX/VMS C assembler V1.00"
20#endif VMS
21
22/*
23 * variables to manage reading the assembly source files
24 */
25char *dotsname; /*the current file name; managed by the parser*/
26int lineno; /*current line number; managed by the parser*/
27char *innames[32]; /*names of the files being assembled*/
28int ninfiles; /*how many interesting files there are*/
29/*
30 * Flags settable from the argv process argument list
31 */
32int silent = 0; /*don't complain about any errors*/
33int savelabels = 0; /*write the labels to the a.out file*/
34int d124 = 4; /*default allocate 4 bytes for unknown pointers*/
35int anyerrs = 0; /*no errors yet*/
36int orgwarn = 0; /*Bad origins*/
37int passno = 1; /* current pass*/
38
39#ifdef DEBUG
40int debug = 0;
41int toktrace = 0;
42#endif
43
44int 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
52char *endcore; /*where to get more symbol space*/
53
54/*
55 * Managers of the a.out file.
56 */
57struct exec hdr;
58#define MAGIC 0410
59u_long tsize; /* total text size */
60u_long dsize; /* total data size */
61u_long datbase; /* base of the data segment */
62u_long trsize; /* total text relocation size */
63u_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 */
72struct exp usedot[NLOC+NLOC]; /* info about all segments */
73struct 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 */
79FILE *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 */
85char *outfile = "a.out";
86FILE *a_out_file;
87off_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 */
97BFILE *usefile[NLOC+NLOC]; /* text/data files */
98BFILE *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 */
145struct relbufdesc *rusefile[NLOC+NLOC];
146struct relbufdesc *relfil; /* un concatnated relocation info */
147BFILE *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
157char *tmpdirprefix =
158#ifdef UNIX
159 "/tmp/";
160#else VMS
161 "/usr/tmp/";
162#endif
163
164#define TMP_SUFFIX "asXXXXXX"
165char tmpn1[TNAMESIZE];
166
167int delexit();
168
169main(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
212argprocess(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 dotsname = "<argv error>";
224 while (argc > 1) {
225 if (argv[1][0] == '-'){
226 cp = argv[1] + 1;
227 /*
228 * We can throw away single minus signs, so
229 * that make scripts for the PDP 11 assembler work
230 * on this assembler too
231 */
232 while (*cp){
233 switch(*cp++){
234 default:
235 yyerror("Unknown flag: %c", *--cp);
236 cp++;
237 break;
238 case 'd':
239 d124 = *cp++ - '0';
240 if ( (d124 != 1) && (d124 != 2) &&
241 (d124 != 4)){
242 yyerror("-d[124] only");
243 exit(1);
244 }
245 break;
246 case 'o':
247 if (argc < 3){
248 yyerror("-o what???");
249 exit(1);
250 }
251 outfile = argv[2];
252 bumpone:
253 argc -= 2;
254 argv += 2;
255 goto nextarg;
256
257 case 't':
258 if (argc < 3){
259 yyerror("-t what???");
260 exit(1);
261 }
262 tmpdirprefix = argv[2];
263 goto bumpone;
264
265 case 'V':
266 useVM = 1;
267 break;
268 case 'W':
269 silent = 1;
270 break;
271 case 'L':
272 savelabels = 1;
273 break;
274#ifdef DEBUG
275 case 'D':
276 debug = 1;
277 break;
278 case 'T':
279 toktrace = 1;
280 break;
281#endif
282 } /*end of the switch*/
283 } /*end of pulling out all arguments*/
284 } /*end of a flag argument*/
285 else { /*file name*/
286 if (ninfiles > 32){
287 yyerror("More than 32 file names");
288 exit(3);
289 }
290 innames[ninfiles++] = argv[1];
291 }
292 --argc; ++argv;
293 nextarg:;
294 }
295}
296
297initialize()
298{
299 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
300 signal(SIGINT, delexit);
301 /*
302 * Install symbols in the table
303 */
304 symtabinit();
305 syminstall();
306 /*
307 * Build the expression parser accelerator token sets
308 */
309 buildtokensets();
310}
311
312zeroorigins()
313{
314 register int locindex;
315 /*
316 * Mark usedot: the first NLOC slots are for named text segments,
317 * the next for named data segments.
318 */
319 for (locindex = 0; locindex < NLOC; locindex++){
320 usedot[locindex].xtype = XTEXT;
321 usedot[NLOC + locindex].xtype = XDATA;
322 usedot[locindex].xvalue = 0;
323 usedot[NLOC + locindex].xvalue = 0;
324 usedot[locindex].yvalue = 0;
325 usedot[NLOC + locindex].yvalue = 0;
326 }
327}
328
329zerolocals()
330{
331 register int i;
332
333 for (i = 0; i <= 9; i++) {
334 lgensym[i] = 1;
335 genref[i] = 0;
336 }
337}
338
339i_pass1()
340{
341 if (useVM == 0){
342 strcat(tmpn1, tmpdirprefix);
343 strcat(tmpn1, TMP_SUFFIX);
344 mktemp(tmpn1);
345 tmpfil = fopen(tmpn1, "w");
346 if (tmpfil==NULL) {
347 yyerror("Bad pass 1 temporary file for writing %s", tmpn1);
348 delexit();
349 }
350 }
351
352 inittmpfile();
353}
354
355pass1()
356{
357 register int i;
358
359 passno = 1;
360 dotp = &usedot[0];
361 txtfil = (BFILE *)0;
362 relfil = (struct relbufdesc *)0;
363
364 if (ninfiles == 0){ /*take the input from stdin directly*/
365 lineno = 1;
366 dotsname = "<stdin>";
367
368 yyparse();
369 } else { /*we have the names tanked*/
370 for (i = 0; i < ninfiles; i++){
371 new_dot_s(innames[i]);
372 if (freopen(innames[i], "r", stdin) == NULL) {
373 yyerror( "Can't open source file %s\n",
374 innames[i]);
375 exit(2);
376 }
377 /* stdio is NOT used to read the input characters */
378 /* we use read directly, into our own buffers */
379 yyparse();
380 }
381 }
382
383 closetmpfile(); /*kick out the last buffered intermediate text*/
384}
385
386testlocals()
387{
388 register int i;
389 for (i = 0; i <= 9; i++) {
390 if (genref[i])
391 yyerror("Reference to undefined local label %df", i);
392 lgensym[i] = 1;
393 genref[i] = 0;
394 }
395}
396
397pass1_5()
398{
399 sortsymtab();
400#ifdef DEBUG
401 if (debug) dumpsymtab();
402#endif
403 jxxxfix();
404#ifdef DEBUG
405 if (debug) dumpsymtab();
406#endif
407}
408
409open_a_out()
410{
411 /*
412 * Open up the a.out file now, and get set to build
413 * up offsets into it for all of the various text,data
414 * text relocation and data relocation segments.
415 */
416 a_out_file = fopen(outfile, "w");
417 if (a_out_file == NULL) {
418 yyerror("Cannot create %s", outfile);
419 delexit();
420 }
421 biofd = a_out_file->_file;
422 a_out_off = 0;
423}
424
425roundsegments()
426{
427 register int locindex;
428 register long v;
429 /*
430 * round and assign text segment origins
431 * the exec header always goes in usefile[0]
432 */
433 tsize = 0;
434 for (locindex=0; locindex<NLOC; locindex++) {
435 v = round(usedot[locindex].xvalue, FW);
436 usedot[locindex].xvalue = tsize;
437 if ((locindex == 0) || (v != 0) ){
438 usefile[locindex] = (BFILE *)Calloc(1, sizeof(BFILE));
439 bopen(usefile[locindex], a_out_off);
440 if (locindex == 0)
441 a_out_off = sizeof (struct exec);
442 } else {
443 usefile[locindex] = (BFILE *)-1;
444 }
445 tsize += v;
446 a_out_off += v;
447 }
448 /*
449 * Round and assign data segment origins.
450 */
451 datbase = round(tsize, PAGRND);
452 for (locindex=0; locindex<NLOC; locindex++) {
453 v = round(usedot[NLOC+locindex].xvalue, FW);
454 usedot[NLOC+locindex].xvalue = datbase + dsize;
455 if (v != 0){
456 usefile[NLOC + locindex] = (BFILE *)Calloc(1,sizeof(BFILE));
457 bopen(usefile[NLOC + locindex], a_out_off);
458 } else {
459 usefile[NLOC + locindex] = (BFILE *)-1;
460 }
461 dsize += v;
462 a_out_off += v;
463 }
464 /*
465 * Assign final values to symbols
466 */
467 hdr.a_bss = dsize;
468 freezesymtab(); /* this touches hdr.a_bss */
469 stabfix();
470 /*
471 * Set up the relocation information "files" to
472 * be zero; outrel takes care of the rest
473 */
474 for (locindex = 0; locindex < NLOC + NLOC; locindex++){
475 rusefile[locindex] = (struct relbufdesc *)0;
476 }
477}
478
479build_hdr()
480{
481 /*
482 * Except for the text and data relocation sizes,
483 * calculate the final values for the header
484 *
485 * Write out the initial copy; we to come
486 * back later and patch up a_trsize and a_drsize,
487 * and overwrite this first version of the header.
488 */
489 hdr.a_magic = MAGIC;
490 hdr.a_text = tsize;
491 hdr.a_data = dsize;
492 hdr.a_bss -= dsize;
493 hdr.a_syms = sizesymtab(); /* Does not include string pool length */
494 hdr.a_entry = 0;
495 hdr.a_trsize = 0;
496 hdr.a_drsize = 0;
497
498 bwrite((char *)&hdr, sizeof(hdr), usefile[0]);
499}
500
501i_pass2()
502{
503 if (useVM == 0) {
504 fclose(tmpfil);
505 tmpfil = fopen(tmpn1, "r");
506 if (tmpfil==NULL) {
507 yyerror("Bad pass 2 temporary file for reading %s", tmpn1);
508 delexit();
509 }
510 }
511}
512
513pass2()
514{
515#ifdef DEBUG
516 if (debug)
517 printf("\n\n\n\t\tPASS 2\n\n\n\n");
518#endif DEBUG
519 passno = 2;
520 lineno = 1;
521 dotp = &usedot[0];
522 txtfil = usefile[0]; /* already opened (always!) */
523 relfil = 0; /* outrel takes care of the rest */
524 initoutrel();
525
526 inittmpfile();
527
528 yyparse();
529
530 closetmpfile();
531}
532
533fillsegments()
534{
535 int locindex;
536 /*
537 * Round text and data segments to FW by appending zeros
538 */
539 for (locindex = 0; locindex < NLOC + NLOC; locindex++) {
540 if (usefile[locindex]) {
541 txtfil = usefile[locindex];
542 dotp = &usedot[locindex];
543 while (usedot[locindex].xvalue & FW)
544 outb(0);
545 }
546 }
547}
548
549reloc_syms()
550{
551 u_long closerelfil();
552 /*
553 * Move the relocation information to a.out
554 * a_out_off is the offset so far:
555 * exec + text segments + data segments
556 */
557 relocfile = (BFILE *)Calloc(1,sizeof(BFILE));
558 bopen(relocfile, a_out_off);
559 a_out_off += closeoutrel(relocfile);
560
561 hdr.a_trsize = trsize;
562 hdr.a_drsize = drsize;
563 /*
564 * Output the symbol table
565 * and if FLEXNAMES is set, the string pool
566 */
567 symwrite(relocfile);
568}
569
570fix_a_out()
571{
572 if (lseek(a_out_file->_file, 0L, 0) < 0)
573 yyerror("Reposition for header rewrite fails");
574 if (write(a_out_file->_file, (char *)&hdr, sizeof (struct exec)) < 0)
575 yyerror("Rewrite of header fails");
576}
577
578delexit()
579{
580 delete();
581 if (passno == 2){
582 unlink(outfile);
583 }
584 exit(1);
585}
586
587delete()
588{
589 if (useVM == 0 || tmpn1[0])
590 unlink(tmpn1);
591}
592
593sawabort()
594{
595 char *fillinbuffer();
596 while (fillinbuffer() != (char *)0)
597 continue;
598 delete();
599 exit(1); /*although the previous pass will also exit non zero*/
600}
601
602panic(fmt, a1, a2, a3, a4)
603 char *fmt;
604 /*VARARGS 1*/
605{
606 yyerror("Assembler panic: bad internal data structure.");
607 yyerror(fmt, a1, a2, a3, a4);
608 delete();
609 abort();
610}