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