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