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) 06/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 V06/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
main(argc,argv)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
argprocess(argc,argv)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 */
selfwhat(place)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
initialize()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
zeroorigins()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
zerolocals()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
i_pass1()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
tempopen(tname,part)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
pass1()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
testlocals()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
pass1_5()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
open_a_out()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
roundsegments()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
build_hdr()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
i_pass2()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
pass2()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
fillsegments()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
reloc_syms()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
fix_a_out()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
delexit()678 delexit()
679 {
680 delete();
681 if (passno == 2){
682 unlink(outfile);
683 }
684 exit(1);
685 }
686
delete()687 delete()
688 {
689 if (useVM == 0 || tokfilename[0])
690 unlink(tokfilename);
691 if (strfilename[0])
692 unlink(strfilename);
693 }
694
sawabort()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
panic(fmt,a1,a2,a3,a4)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 }
713