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