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