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