use struct nlist; change field names; vgrind format fixes
[unix-history] / usr / src / old / as.vax / asmain.c
CommitLineData
59e14996 1/* Copyright (c) 1980 Regents of the University of California */
451260e7 2static char sccsid[] = "@(#)asmain.c 4.2 %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*/
36
37#ifdef DEBUG
38int debug = 0;
39int toktrace = 0;
40#endif
41
42int 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
50char *endcore; /*where to get more symbol space*/
51
52/*
53 * Managers of the a.out file.
54 */
55struct exec hdr;
56#define MAGIC 0410
57u_long tsize; /* total text size */
58u_long dsize; /* total data size */
59u_long datbase; /* base of the data segment */
60u_long trsize; /* total text relocation size */
61u_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 */
70struct exp usedot[NLOC+NLOC]; /* info about all segments */
71struct 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 */
77FILE *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 */
83char *outfile = "a.out";
84FILE *a_out_file;
85off_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 */
95BFILE *usefile[NLOC+NLOC]; /* text/data files */
96BFILE *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 */
143struct relbufdesc *rusefile[NLOC+NLOC];
144struct relbufdesc *relfil; /* un concatnated relocation info */
145BFILE *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
155char *tmpdirprefix =
156#ifdef UNIX
157 "/tmp/";
158#else VMS
159 "/usr/tmp/";
160#endif
161
162#define TMP_SUFFIX "asXXXXXX"
163char tmpn1[TNAMESIZE];
164
165int delexit();
166
167main(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
210argprocess(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
295initialize()
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
310zeroorigins()
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++){
451260e7
RH
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;
59e14996
BJ
324 }
325}
326
327zerolocals()
328{
329 register int i;
330
331 for (i = 0; i <= 9; i++) {
332 lgensym[i] = 1;
333 genref[i] = 0;
334 }
335}
336
337i_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
353pass1()
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
384testlocals()
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
395pass1_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
407open_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
423roundsegments()
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++) {
451260e7
RH
433 v = round(usedot[locindex].e_xvalue, FW);
434 usedot[locindex].e_xvalue = tsize;
59e14996
BJ
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++) {
451260e7
RH
451 v = round(usedot[NLOC+locindex].e_xvalue, FW);
452 usedot[NLOC+locindex].e_xvalue = datbase + dsize;
59e14996
BJ
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
477build_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
499i_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
511pass2()
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
531fillsegments()
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];
451260e7 541 while (usedot[locindex].e_xvalue & FW)
59e14996
BJ
542 outb(0);
543 }
544 }
545}
546
547reloc_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
568fix_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
576delexit()
577{
578 delete();
579 if (passno == 2){
580 unlink(outfile);
581 }
582 exit(1);
583}
584
585delete()
586{
587 if (useVM == 0 || tmpn1[0])
588 unlink(tmpn1);
589}
590
591sawabort()
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
600panic(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}