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