need dependency, from Chris Torek
[unix-history] / usr / src / old / as.vax / asmain.c
CommitLineData
f70ab843 1/*
e170e18b
DF
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.
f70ab843 5 */
e170e18b
DF
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1982 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
f70ab843 13#ifndef lint
682bc55a 14static char sccsid[] = "@(#)asmain.c 5.5 (Berkeley) %G%";
f70ab843
RH
15#endif not lint
16
59e14996
BJ
17#include <stdio.h>
18#include <ctype.h>
59e14996 19#include <signal.h>
59e14996
BJ
20
21#include "as.h"
22#include "assyms.h"
59e14996 23#include "asscan.h"
f70ab843 24#include "asexpr.h"
5256e64e 25#include <paths.h>
59e14996 26
8192c7f0
RC
27#include <sys/stat.h>
28
682bc55a 29#define unix_lang_name "VAX/UNIX Assembler V%G% 5.5"
59e14996
BJ
30/*
31 * variables to manage reading the assembly source files
32 */
33char *dotsname; /*the current file name; managed by the parser*/
34int lineno; /*current line number; managed by the parser*/
100d3f3c 35char **innames; /*names of the files being assembled*/
59e14996
BJ
36int ninfiles; /*how many interesting files there are*/
37/*
38 * Flags settable from the argv process argument list
39 */
40int silent = 0; /*don't complain about any errors*/
41int savelabels = 0; /*write the labels to the a.out file*/
42int d124 = 4; /*default allocate 4 bytes for unknown pointers*/
ea01d993 43int maxalign = 2; /*default .align maximum*/
59e14996 44int anyerrs = 0; /*no errors yet*/
f70ab843 45int anywarnings=0; /*no warnings yet*/
59e14996
BJ
46int orgwarn = 0; /*Bad origins*/
47int passno = 1; /* current pass*/
e5b9ebfb 48int jxxxJUMP = 0; /* in jxxxes that branch too far, use jmp instead of brw */
ed84d47b 49int readonlydata = 0; /* initialzed data -> text space */
59e14996 50
f70ab843
RH
51int nGHnumbers = 0; /* GH numbers used */
52int nGHopcodes = 0; /* GH opcodes used */
53int nnewopcodes = 0; /* new opcodes used */
54
59e14996
BJ
55#ifdef DEBUG
56int debug = 0;
57int toktrace = 0;
58#endif
59
e40ffc5c 60int useVM = 0;
59e14996
BJ
61
62char *endcore; /*where to get more symbol space*/
63
64/*
65 * Managers of the a.out file.
66 */
67struct exec hdr;
ed84d47b 68#define MAGIC 0407
59e14996
BJ
69u_long tsize; /* total text size */
70u_long dsize; /* total data size */
71u_long datbase; /* base of the data segment */
72u_long trsize; /* total text relocation size */
73u_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 */
82struct exp usedot[NLOC+NLOC]; /* info about all segments */
83struct exp *dotp; /* data/text location pointer */
84/*
ec43bca4 85 * The inter pass temporary token file is opened and closed by stdio, but
59e14996
BJ
86 * is written to using direct read/write, as the temporary file
87 * is composed of buffers exactly BUFSIZ long.
88 */
ec43bca4
RH
89FILE *tokfile; /* interpass communication file */
90char 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 */
95FILE *strfile; /* interpass string file */
96char strfilename[TNAMESIZE];
97int strfilepos = 0; /* position within the string file */
59e14996
BJ
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 */
682bc55a 103char *outfile;
59e14996
BJ
104FILE *a_out_file;
105off_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 */
115BFILE *usefile[NLOC+NLOC]; /* text/data files */
116BFILE *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 */
163struct relbufdesc *rusefile[NLOC+NLOC];
164struct relbufdesc *relfil; /* un concatnated relocation info */
165BFILE *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 */
e40ffc5c 174char *tmpdirprefix = "/tmp/";
59e14996
BJ
175int delexit();
176
177main(argc, argv)
178 int argc;
179 char **argv;
180{
f70ab843 181 char *sbrk();
59e14996 182
ec43bca4
RH
183 tokfilename[0] = 0;
184 strfilename[0] = 0;
f70ab843 185 endcore = sbrk(0);
59e14996
BJ
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 */
7a5aec15 203 roundsegments(); /* round segments to FW */
59e14996
BJ
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
7a5aec15 210 fillsegments(); /* fill segments with 0 to FW */
59e14996
BJ
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");
f70ab843
RH
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
59e14996 229 exit(anyerrs != 0);
e40ffc5c 230}
59e14996
BJ
231
232argprocess(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
682bc55a 243 outfile = (char *)genbuildname("a.out");
100d3f3c 244 innames = (char **)ClearCalloc(argc+1, sizeof (innames[0]));
59e14996
BJ
245 dotsname = "<argv error>";
246 while (argc > 1) {
100d3f3c
BJ
247 if (argv[1][0] != '-')
248 innames[ninfiles++] = argv[1];
249 else {
59e14996
BJ
250 cp = argv[1] + 1;
251 /*
252 * We can throw away single minus signs, so
253 * that make scripts for the PDP 11 assembler work
254 * on this assembler too
255 */
256 while (*cp){
257 switch(*cp++){
258 default:
259 yyerror("Unknown flag: %c", *--cp);
260 cp++;
261 break;
26c6a2ae
RH
262 case 'v':
263 selfwhat(stdout);
264 exit(1);
59e14996
BJ
265 case 'd':
266 d124 = *cp++ - '0';
267 if ( (d124 != 1) && (d124 != 2) &&
268 (d124 != 4)){
269 yyerror("-d[124] only");
270 exit(1);
271 }
272 break;
ea01d993
RH
273 case 'a':
274 maxalign = atoi(cp+1);
275 for (cp++; isdigit(*cp); cp++)
276 /*VOID*/;
277 if ( (maxalign > 16) || (maxalign < 0)){
278 yyerror("-a: 0<=align<=16");
279 exit(1);
280 }
281 break;
59e14996
BJ
282 case 'o':
283 if (argc < 3){
284 yyerror("-o what???");
285 exit(1);
286 }
682bc55a 287 outfile = (char *)genbuildname(argv[2]);
59e14996
BJ
288 bumpone:
289 argc -= 2;
290 argv += 2;
291 goto nextarg;
292
293 case 't':
294 if (argc < 3){
295 yyerror("-t what???");
296 exit(1);
297 }
298 tmpdirprefix = argv[2];
299 goto bumpone;
300
301 case 'V':
302 useVM = 1;
303 break;
304 case 'W':
305 silent = 1;
306 break;
307 case 'L':
308 savelabels = 1;
309 break;
e5b9ebfb
RH
310 case 'J':
311 jxxxJUMP = 1;
312 break;
59e14996
BJ
313#ifdef DEBUG
314 case 'D':
315 debug = 1;
316 break;
317 case 'T':
318 toktrace = 1;
319 break;
320#endif
ed84d47b
BJ
321 case 'R':
322 readonlydata = 1;
323 break;
59e14996
BJ
324 } /*end of the switch*/
325 } /*end of pulling out all arguments*/
326 } /*end of a flag argument*/
59e14996
BJ
327 --argc; ++argv;
328 nextarg:;
329 }
100d3f3c 330 /* innames[ninfiles] = 0; */
59e14996 331}
26c6a2ae
RH
332/*
333 * poke through the data space and find all sccs identifiers.
334 * We assume:
335 * a) that extern char **environ; is the first thing in the bss
336 * segment (true, if one is using the new version of cmgt.crt0.c)
337 * b) that the sccsid's have not been put into text space.
338 */
339selfwhat(place)
340 FILE *place;
341{
342 extern char **environ;
343 register char *ub;
344 register char *cp;
345 register char *pat;
346 char *sbrk();
347
348 for (cp = (char *)&environ, ub = sbrk(0); cp < ub; cp++){
349 if (cp[0] != '@') continue;
350 if (cp[1] != '(') continue;
351 if (cp[2] != '#') continue;
352 if (cp[3] != ')') continue;
353 fputc('\t', place);
354 for (cp += 4; cp < ub; cp++){
355 if (*cp == 0) break;
356 if (*cp == '>') break;
357 if (*cp == '\n') break;
358 fputc(*cp, place);
359 }
360 fputc('\n', place);
361 }
362}
59e14996
BJ
363
364initialize()
365{
366 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
367 signal(SIGINT, delexit);
368 /*
369 * Install symbols in the table
370 */
371 symtabinit();
372 syminstall();
373 /*
374 * Build the expression parser accelerator token sets
375 */
376 buildtokensets();
377}
378
379zeroorigins()
380{
381 register int locindex;
382 /*
383 * Mark usedot: the first NLOC slots are for named text segments,
384 * the next for named data segments.
385 */
386 for (locindex = 0; locindex < NLOC; locindex++){
451260e7
RH
387 usedot[locindex].e_xtype = XTEXT;
388 usedot[NLOC + locindex].e_xtype = XDATA;
389 usedot[locindex].e_xvalue = 0;
390 usedot[NLOC + locindex].e_xvalue = 0;
59e14996
BJ
391 }
392}
393
394zerolocals()
395{
396 register int i;
397
398 for (i = 0; i <= 9; i++) {
399 lgensym[i] = 1;
400 genref[i] = 0;
401 }
402}
403
404i_pass1()
405{
ec43bca4
RH
406 FILE *tempopen();
407 if (useVM == 0)
408 tokfile = tempopen(tokfilename, "T");
409 strfile = tempopen(strfilename, "S");
410 /*
411 * write out the string length.
412 * This will be overwritten when the
413 * strings are tacked onto the growing a.out file
414 */
415 strfilepos = sizeof(int);
416 fwrite(&strfilepos, sizeof(int), 1, strfile);
59e14996 417
ec43bca4 418 inittokfile();
e5b9ebfb 419 initijxxx();
59e14996
BJ
420}
421
ec43bca4
RH
422FILE *tempopen(tname, part)
423 char *tname;
424 char *part;
425{
426 FILE *file;
6521d648 427 (void)sprintf(tname, "%s%sas%s%05d",
ec43bca4 428 tmpdirprefix,
91425db3 429 (tmpdirprefix[strlen(tmpdirprefix)-1] != '/') ? "/" : "",
ec43bca4
RH
430 part,
431 getpid());
432 file = fopen(tname, "w");
433 if (file == NULL) {
434 yyerror("Bad pass 1 temporary file for writing %s", tname);
435 delexit();
436 }
437 return(file);
438}
439
59e14996
BJ
440pass1()
441{
442 register int i;
443
444 passno = 1;
445 dotp = &usedot[0];
446 txtfil = (BFILE *)0;
447 relfil = (struct relbufdesc *)0;
448
449 if (ninfiles == 0){ /*take the input from stdin directly*/
450 lineno = 1;
451 dotsname = "<stdin>";
452
453 yyparse();
454 } else { /*we have the names tanked*/
455 for (i = 0; i < ninfiles; i++){
456 new_dot_s(innames[i]);
457 if (freopen(innames[i], "r", stdin) == NULL) {
458 yyerror( "Can't open source file %s\n",
459 innames[i]);
460 exit(2);
461 }
462 /* stdio is NOT used to read the input characters */
463 /* we use read directly, into our own buffers */
464 yyparse();
465 }
466 }
467
ec43bca4 468 closetokfile(); /*kick out the last buffered intermediate text*/
59e14996
BJ
469}
470
471testlocals()
472{
473 register int i;
474 for (i = 0; i <= 9; i++) {
475 if (genref[i])
476 yyerror("Reference to undefined local label %df", i);
477 lgensym[i] = 1;
478 genref[i] = 0;
479 }
480}
481
482pass1_5()
483{
484 sortsymtab();
485#ifdef DEBUG
486 if (debug) dumpsymtab();
487#endif
488 jxxxfix();
489#ifdef DEBUG
490 if (debug) dumpsymtab();
491#endif
492}
493
494open_a_out()
495{
8192c7f0
RC
496 struct stat stb;
497
59e14996
BJ
498 /*
499 * Open up the a.out file now, and get set to build
500 * up offsets into it for all of the various text,data
501 * text relocation and data relocation segments.
502 */
503 a_out_file = fopen(outfile, "w");
504 if (a_out_file == NULL) {
505 yyerror("Cannot create %s", outfile);
506 delexit();
507 }
508 biofd = a_out_file->_file;
8192c7f0
RC
509 fstat(biofd, &stb);
510 biobufsize = stb.st_blksize;
59e14996
BJ
511 a_out_off = 0;
512}
513
514roundsegments()
515{
516 register int locindex;
517 register long v;
518 /*
519 * round and assign text segment origins
520 * the exec header always goes in usefile[0]
521 */
522 tsize = 0;
523 for (locindex=0; locindex<NLOC; locindex++) {
7a5aec15 524 v = round(usedot[locindex].e_xvalue, FW);
451260e7 525 usedot[locindex].e_xvalue = tsize;
59e14996
BJ
526 if ((locindex == 0) || (v != 0) ){
527 usefile[locindex] = (BFILE *)Calloc(1, sizeof(BFILE));
528 bopen(usefile[locindex], a_out_off);
529 if (locindex == 0)
530 a_out_off = sizeof (struct exec);
531 } else {
532 usefile[locindex] = (BFILE *)-1;
533 }
534 tsize += v;
535 a_out_off += v;
536 }
537 /*
538 * Round and assign data segment origins.
539 */
7a5aec15 540 datbase = round(tsize, FW);
59e14996 541 for (locindex=0; locindex<NLOC; locindex++) {
7a5aec15 542 v = round(usedot[NLOC+locindex].e_xvalue, FW);
451260e7 543 usedot[NLOC+locindex].e_xvalue = datbase + dsize;
59e14996
BJ
544 if (v != 0){
545 usefile[NLOC + locindex] = (BFILE *)Calloc(1,sizeof(BFILE));
546 bopen(usefile[NLOC + locindex], a_out_off);
547 } else {
548 usefile[NLOC + locindex] = (BFILE *)-1;
549 }
550 dsize += v;
551 a_out_off += v;
552 }
553 /*
554 * Assign final values to symbols
555 */
556 hdr.a_bss = dsize;
557 freezesymtab(); /* this touches hdr.a_bss */
558 stabfix();
559 /*
560 * Set up the relocation information "files" to
561 * be zero; outrel takes care of the rest
562 */
563 for (locindex = 0; locindex < NLOC + NLOC; locindex++){
564 rusefile[locindex] = (struct relbufdesc *)0;
565 }
566}
567
568build_hdr()
569{
570 /*
571 * Except for the text and data relocation sizes,
572 * calculate the final values for the header
573 *
574 * Write out the initial copy; we to come
575 * back later and patch up a_trsize and a_drsize,
576 * and overwrite this first version of the header.
577 */
578 hdr.a_magic = MAGIC;
579 hdr.a_text = tsize;
580 hdr.a_data = dsize;
581 hdr.a_bss -= dsize;
582 hdr.a_syms = sizesymtab(); /* Does not include string pool length */
583 hdr.a_entry = 0;
584 hdr.a_trsize = 0;
585 hdr.a_drsize = 0;
586
587 bwrite((char *)&hdr, sizeof(hdr), usefile[0]);
588}
589
590i_pass2()
591{
592 if (useVM == 0) {
ec43bca4
RH
593 fclose(tokfile);
594 tokfile = fopen(tokfilename, "r");
595 if (tokfile==NULL) {
596 yyerror("Bad pass 2 temporary file for reading %s", tokfilename);
59e14996
BJ
597 delexit();
598 }
599 }
ec43bca4
RH
600 fclose(strfile);
601 strfile = fopen(strfilename, "r");
59e14996
BJ
602}
603
604pass2()
605{
606#ifdef DEBUG
607 if (debug)
608 printf("\n\n\n\t\tPASS 2\n\n\n\n");
609#endif DEBUG
610 passno = 2;
611 lineno = 1;
612 dotp = &usedot[0];
613 txtfil = usefile[0]; /* already opened (always!) */
614 relfil = 0; /* outrel takes care of the rest */
615 initoutrel();
616
ec43bca4 617 inittokfile();
59e14996
BJ
618
619 yyparse();
620
ec43bca4 621 closetokfile();
59e14996
BJ
622}
623
624fillsegments()
625{
626 int locindex;
627 /*
7a5aec15 628 * Round text and data segments to FW by appending zeros
59e14996
BJ
629 */
630 for (locindex = 0; locindex < NLOC + NLOC; locindex++) {
631 if (usefile[locindex]) {
632 txtfil = usefile[locindex];
633 dotp = &usedot[locindex];
7a5aec15 634 while (usedot[locindex].e_xvalue & FW)
59e14996
BJ
635 outb(0);
636 }
637 }
638}
639
640reloc_syms()
641{
642 u_long closerelfil();
643 /*
644 * Move the relocation information to a.out
645 * a_out_off is the offset so far:
646 * exec + text segments + data segments
647 */
648 relocfile = (BFILE *)Calloc(1,sizeof(BFILE));
649 bopen(relocfile, a_out_off);
650 a_out_off += closeoutrel(relocfile);
651
652 hdr.a_trsize = trsize;
653 hdr.a_drsize = drsize;
ed84d47b
BJ
654 if (readonlydata) {
655 hdr.a_text += hdr.a_data;
656 hdr.a_data = 0;
657 hdr.a_trsize += hdr.a_drsize;
658 hdr.a_drsize = 0;
659 }
59e14996 660 /*
28219de3 661 * Output the symbol table and the string pool
ec43bca4
RH
662 *
663 * We must first rewind the string pool file to its beginning,
664 * in case it was seek'ed into for fetching ascii and asciz
665 * strings.
59e14996 666 */
ec43bca4 667 fseek(strfile, 0, 0);
59e14996
BJ
668 symwrite(relocfile);
669}
670
671fix_a_out()
672{
f70ab843 673 if (lseek(a_out_file->_file, 0L, 0) < 0L)
59e14996
BJ
674 yyerror("Reposition for header rewrite fails");
675 if (write(a_out_file->_file, (char *)&hdr, sizeof (struct exec)) < 0)
676 yyerror("Rewrite of header fails");
677}
678
679delexit()
680{
681 delete();
682 if (passno == 2){
683 unlink(outfile);
684 }
685 exit(1);
686}
687
688delete()
689{
ec43bca4
RH
690 if (useVM == 0 || tokfilename[0])
691 unlink(tokfilename);
692 if (strfilename[0])
693 unlink(strfilename);
59e14996
BJ
694}
695
696sawabort()
697{
698 char *fillinbuffer();
699 while (fillinbuffer() != (char *)0)
700 continue;
701 delete();
702 exit(1); /*although the previous pass will also exit non zero*/
703}
704
705panic(fmt, a1, a2, a3, a4)
706 char *fmt;
707 /*VARARGS 1*/
708{
709 yyerror("Assembler panic: bad internal data structure.");
710 yyerror(fmt, a1, a2, a3, a4);
711 delete();
712 abort();
713}