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