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