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