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