1596Sbill /* Copyright (c) 1980 Regents of the University of California */ 2*636Shenry static char sccsid[] = "@(#)asmain.c 4.3 08/15/80"; 3596Sbill #include <stdio.h> 4596Sbill #include <ctype.h> 5596Sbill #include <signal.h> 6596Sbill 7596Sbill #include "as.h" 8596Sbill #include "assyms.h" 9596Sbill #include "asexpr.h" 10596Sbill #include "asscan.h" 11596Sbill 12596Sbill #ifdef UNIX 13631Shenry #define unix_lang_name "VAX/UNIX Assembler Vasmain.c" 14596Sbill #endif 15596Sbill 16596Sbill #ifdef VMS 17631Shenry #define vms_lang_name "VAX/VMS C Assembler V1.00" 18596Sbill #endif VMS 19596Sbill 20596Sbill /* 21596Sbill * variables to manage reading the assembly source files 22596Sbill */ 23596Sbill char *dotsname; /*the current file name; managed by the parser*/ 24596Sbill int lineno; /*current line number; managed by the parser*/ 25596Sbill char *innames[32]; /*names of the files being assembled*/ 26596Sbill int ninfiles; /*how many interesting files there are*/ 27596Sbill /* 28596Sbill * Flags settable from the argv process argument list 29596Sbill */ 30596Sbill int silent = 0; /*don't complain about any errors*/ 31596Sbill int savelabels = 0; /*write the labels to the a.out file*/ 32596Sbill int d124 = 4; /*default allocate 4 bytes for unknown pointers*/ 33596Sbill int anyerrs = 0; /*no errors yet*/ 34596Sbill int orgwarn = 0; /*Bad origins*/ 35596Sbill int passno = 1; /* current pass*/ 36*636Shenry int jxxxJUMP = 0; /* in jxxxes that branch too far, use jmp instead of brw */ 37596Sbill 38596Sbill #ifdef DEBUG 39596Sbill int debug = 0; 40596Sbill int toktrace = 0; 41596Sbill #endif 42596Sbill 43596Sbill int useVM = /*put the temp file in virtual memory*/ 44596Sbill #ifdef VMS 45596Sbill 1; /*VMS has virtual memory (duh)*/ 46596Sbill #endif VMS 47596Sbill #ifdef UNIX 48596Sbill 0; 49596Sbill #endif 50596Sbill 51596Sbill char *endcore; /*where to get more symbol space*/ 52596Sbill 53596Sbill /* 54596Sbill * Managers of the a.out file. 55596Sbill */ 56596Sbill struct exec hdr; 57596Sbill #define MAGIC 0410 58596Sbill u_long tsize; /* total text size */ 59596Sbill u_long dsize; /* total data size */ 60596Sbill u_long datbase; /* base of the data segment */ 61596Sbill u_long trsize; /* total text relocation size */ 62596Sbill u_long drsize; /* total data relocation size */ 63596Sbill 64596Sbill /* 65596Sbill * Information about the current segment is accumulated in 66596Sbill * usedot; the most important information stored is the 67596Sbill * accumulated size of each of the text and data segments 68596Sbill * 69596Sbill * dotp points to the correct usedot expression for the current segment 70596Sbill */ 71596Sbill struct exp usedot[NLOC+NLOC]; /* info about all segments */ 72596Sbill struct exp *dotp; /* data/text location pointer */ 73596Sbill /* 74596Sbill * The inter pass temporary file is opened and closed by stdio, but 75596Sbill * is written to using direct read/write, as the temporary file 76596Sbill * is composed of buffers exactly BUFSIZ long. 77596Sbill */ 78596Sbill FILE *tmpfil; /* interpass communication file */ 79596Sbill /* 80596Sbill * a.out is created during the second pass. 81596Sbill * It is opened by stdio, but is filled with the parallel 82596Sbill * block I/O library 83596Sbill */ 84596Sbill char *outfile = "a.out"; 85596Sbill FILE *a_out_file; 86596Sbill off_t a_out_off; /* cumulative offsets for segments */ 87596Sbill /* 88596Sbill * The logical files containing the assembled data for each of 89596Sbill * the text and data segments are 90596Sbill * managed by the parallel block I/O library. 91596Sbill * a.out is logically opened in many places at once to 92596Sbill * receive the assembled data from the various segments as 93596Sbill * it all trickles in, but is physically opened only once 94596Sbill * to minimize file overhead. 95596Sbill */ 96596Sbill BFILE *usefile[NLOC+NLOC]; /* text/data files */ 97596Sbill BFILE *txtfil; /* current text/data file */ 98596Sbill /* 99596Sbill * Relocation information is accumulated seperately for each 100596Sbill * segment. This is required by the old loader (from BTL), 101596Sbill * but not by the new loader (Bill Joy). 102596Sbill * 103596Sbill * However, the size of the relocation information can not be computed 104596Sbill * during or after the 1st pass because the ''absoluteness' of values 105596Sbill * is unknown until all locally declared symbols have been seen. 106596Sbill * Thus, the size of the relocation information is only 107596Sbill * known after the second pass is finished. 108596Sbill * This obviates the use of the block I/O 109596Sbill * library, which requires knowing the exact offsets in a.out. 110596Sbill * 111596Sbill * So, we save the relocation information internally (we don't 112596Sbill * go to internal files to minimize overhead). 113596Sbill * 114596Sbill * Empirically, we studied 259 files composing the system, 115596Sbill * two compilers and a compiler generator: (all of which have 116596Sbill * fairly large source files) 117596Sbill * 118596Sbill * Number of files = 259 119596Sbill * Number of non zero text reloc files: 233 120596Sbill * Number of non zero data reloc files: 53 121596Sbill * Average text relocation = 889 122596Sbill * Average data relocation = 346 123596Sbill * Number of files > BUFSIZ text relocation = 71 124596Sbill * Number of files > BUFSIZ data relocation = 6 125596Sbill * 126596Sbill * For compiled C code, there is usually one text segment and two 127596Sbill * data segments; we see that allocating our own buffers and 128596Sbill * doing our internal handling of relocation information will, 129596Sbill * on the average, not use more memory than taken up by the buffers 130596Sbill * allocated for doing file I/O in parallel to a number of file. 131596Sbill * 132596Sbill * If we are assembling with the -V option, we 133596Sbill * use the left over token buffers from the 2nd pass, 134596Sbill * otherwise, we create our own. 135596Sbill * 136596Sbill * When the 2nd pass is complete, closeoutrel flushes the token 137596Sbill * buffers out to a BFILE. 138596Sbill * 139596Sbill * The internals to relbufdesc are known only in assyms.c 140596Sbill * 141596Sbill * outrel constructs the relocation information. 142596Sbill * closeoutrel flushes the relocation information to relfil. 143596Sbill */ 144596Sbill struct relbufdesc *rusefile[NLOC+NLOC]; 145596Sbill struct relbufdesc *relfil; /* un concatnated relocation info */ 146596Sbill BFILE *relocfile; /* concatnated relocation info */ 147596Sbill /* 148596Sbill * Once the relocation information has been written, 149596Sbill * we can write out the symbol table using the Block I/O 150596Sbill * mechanisms, as we once again know the offsets into 151596Sbill * the a.out file. 152596Sbill * 153596Sbill * We use relfil to output the symbol table information. 154596Sbill */ 155596Sbill 156596Sbill char *tmpdirprefix = 157596Sbill #ifdef UNIX 158596Sbill "/tmp/"; 159596Sbill #else VMS 160596Sbill "/usr/tmp/"; 161596Sbill #endif 162596Sbill 163596Sbill #define TMP_SUFFIX "asXXXXXX" 164596Sbill char tmpn1[TNAMESIZE]; 165596Sbill 166596Sbill int delexit(); 167596Sbill 168596Sbill main(argc, argv) 169596Sbill int argc; 170596Sbill char **argv; 171596Sbill { 172596Sbill 173596Sbill tmpn1[0] = 0; 174596Sbill endcore = (char *)sbrk(0); 175596Sbill 176596Sbill argprocess(argc, argv); /* process argument lists */ 177596Sbill if (anyerrs) exit(1); 178596Sbill 179596Sbill initialize(); 180596Sbill zeroorigins(); /* set origins to zero */ 181596Sbill zerolocals(); /* fix local label counters */ 182596Sbill 183596Sbill i_pass1(); /* open temp files, etc */ 184596Sbill pass1(); /* first pass through .s files */ 185596Sbill testlocals(); /* check for undefined locals */ 186596Sbill if (anyerrs) delexit(); 187596Sbill 188596Sbill pass1_5(); /* resolve jxxx */ 189596Sbill if (anyerrs) delexit(); 190596Sbill 191596Sbill open_a_out(); /* open a.out */ 192596Sbill roundsegments(); /* round segments to FW */ 193596Sbill build_hdr(); /* build initial header, and output */ 194596Sbill 195596Sbill i_pass2(); /* reopen temporary file, etc */ 196596Sbill pass2(); /* second pass through the virtual .s */ 197596Sbill if (anyerrs) delexit(); 198596Sbill 199596Sbill fillsegments(); /* fill segments with 0 to FW */ 200596Sbill reloc_syms(); /* dump relocation and symbol table */ 201596Sbill 202596Sbill delete(); /* remove tmp file */ 203596Sbill bflush(); /* close off block I/O view of a.out */ 204596Sbill fix_a_out(); /* add in text and data reloc counts */ 205596Sbill 206596Sbill if (anyerrs == 0 && orgwarn) 207596Sbill yyerror("Caution: absolute origins.\n"); 208596Sbill exit(anyerrs != 0); 209596Sbill } /*end of UNIX main*/ 210596Sbill 211596Sbill argprocess(argc, argv) 212596Sbill int argc; 213596Sbill char *argv[]; 214596Sbill { 215596Sbill register char *cp; 216596Sbill 217596Sbill ninfiles = 0; 218596Sbill silent = 0; 219596Sbill #ifdef DEBUG 220596Sbill debug = 0; 221596Sbill #endif 222596Sbill dotsname = "<argv error>"; 223596Sbill while (argc > 1) { 224596Sbill if (argv[1][0] == '-'){ 225596Sbill cp = argv[1] + 1; 226596Sbill /* 227596Sbill * We can throw away single minus signs, so 228596Sbill * that make scripts for the PDP 11 assembler work 229596Sbill * on this assembler too 230596Sbill */ 231596Sbill while (*cp){ 232596Sbill switch(*cp++){ 233596Sbill default: 234596Sbill yyerror("Unknown flag: %c", *--cp); 235596Sbill cp++; 236596Sbill break; 237596Sbill case 'd': 238596Sbill d124 = *cp++ - '0'; 239596Sbill if ( (d124 != 1) && (d124 != 2) && 240596Sbill (d124 != 4)){ 241596Sbill yyerror("-d[124] only"); 242596Sbill exit(1); 243596Sbill } 244596Sbill break; 245596Sbill case 'o': 246596Sbill if (argc < 3){ 247596Sbill yyerror("-o what???"); 248596Sbill exit(1); 249596Sbill } 250596Sbill outfile = argv[2]; 251596Sbill bumpone: 252596Sbill argc -= 2; 253596Sbill argv += 2; 254596Sbill goto nextarg; 255596Sbill 256596Sbill case 't': 257596Sbill if (argc < 3){ 258596Sbill yyerror("-t what???"); 259596Sbill exit(1); 260596Sbill } 261596Sbill tmpdirprefix = argv[2]; 262596Sbill goto bumpone; 263596Sbill 264596Sbill case 'V': 265596Sbill useVM = 1; 266596Sbill break; 267596Sbill case 'W': 268596Sbill silent = 1; 269596Sbill break; 270596Sbill case 'L': 271596Sbill savelabels = 1; 272596Sbill break; 273*636Shenry case 'J': 274*636Shenry jxxxJUMP = 1; 275*636Shenry break; 276596Sbill #ifdef DEBUG 277596Sbill case 'D': 278596Sbill debug = 1; 279596Sbill break; 280596Sbill case 'T': 281596Sbill toktrace = 1; 282596Sbill break; 283596Sbill #endif 284596Sbill } /*end of the switch*/ 285596Sbill } /*end of pulling out all arguments*/ 286596Sbill } /*end of a flag argument*/ 287596Sbill else { /*file name*/ 288596Sbill if (ninfiles > 32){ 289596Sbill yyerror("More than 32 file names"); 290596Sbill exit(3); 291596Sbill } 292596Sbill innames[ninfiles++] = argv[1]; 293596Sbill } 294596Sbill --argc; ++argv; 295596Sbill nextarg:; 296596Sbill } 297596Sbill } 298596Sbill 299596Sbill initialize() 300596Sbill { 301596Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 302596Sbill signal(SIGINT, delexit); 303596Sbill /* 304596Sbill * Install symbols in the table 305596Sbill */ 306596Sbill symtabinit(); 307596Sbill syminstall(); 308596Sbill /* 309596Sbill * Build the expression parser accelerator token sets 310596Sbill */ 311596Sbill buildtokensets(); 312596Sbill } 313596Sbill 314596Sbill zeroorigins() 315596Sbill { 316596Sbill register int locindex; 317596Sbill /* 318596Sbill * Mark usedot: the first NLOC slots are for named text segments, 319596Sbill * the next for named data segments. 320596Sbill */ 321596Sbill for (locindex = 0; locindex < NLOC; locindex++){ 322631Shenry usedot[locindex].e_xtype = XTEXT; 323631Shenry usedot[NLOC + locindex].e_xtype = XDATA; 324631Shenry usedot[locindex].e_xvalue = 0; 325631Shenry usedot[NLOC + locindex].e_xvalue = 0; 326631Shenry usedot[locindex].e_yvalue = 0; 327631Shenry usedot[NLOC + locindex].e_yvalue = 0; 328596Sbill } 329596Sbill } 330596Sbill 331596Sbill zerolocals() 332596Sbill { 333596Sbill register int i; 334596Sbill 335596Sbill for (i = 0; i <= 9; i++) { 336596Sbill lgensym[i] = 1; 337596Sbill genref[i] = 0; 338596Sbill } 339596Sbill } 340596Sbill 341596Sbill i_pass1() 342596Sbill { 343596Sbill if (useVM == 0){ 344596Sbill strcat(tmpn1, tmpdirprefix); 345596Sbill strcat(tmpn1, TMP_SUFFIX); 346596Sbill mktemp(tmpn1); 347596Sbill tmpfil = fopen(tmpn1, "w"); 348596Sbill if (tmpfil==NULL) { 349596Sbill yyerror("Bad pass 1 temporary file for writing %s", tmpn1); 350596Sbill delexit(); 351596Sbill } 352596Sbill } 353596Sbill 354596Sbill inittmpfile(); 355*636Shenry initijxxx(); 356596Sbill } 357596Sbill 358596Sbill pass1() 359596Sbill { 360596Sbill register int i; 361596Sbill 362596Sbill passno = 1; 363596Sbill dotp = &usedot[0]; 364596Sbill txtfil = (BFILE *)0; 365596Sbill relfil = (struct relbufdesc *)0; 366596Sbill 367596Sbill if (ninfiles == 0){ /*take the input from stdin directly*/ 368596Sbill lineno = 1; 369596Sbill dotsname = "<stdin>"; 370596Sbill 371596Sbill yyparse(); 372596Sbill } else { /*we have the names tanked*/ 373596Sbill for (i = 0; i < ninfiles; i++){ 374596Sbill new_dot_s(innames[i]); 375596Sbill if (freopen(innames[i], "r", stdin) == NULL) { 376596Sbill yyerror( "Can't open source file %s\n", 377596Sbill innames[i]); 378596Sbill exit(2); 379596Sbill } 380596Sbill /* stdio is NOT used to read the input characters */ 381596Sbill /* we use read directly, into our own buffers */ 382596Sbill yyparse(); 383596Sbill } 384596Sbill } 385596Sbill 386596Sbill closetmpfile(); /*kick out the last buffered intermediate text*/ 387596Sbill } 388596Sbill 389596Sbill testlocals() 390596Sbill { 391596Sbill register int i; 392596Sbill for (i = 0; i <= 9; i++) { 393596Sbill if (genref[i]) 394596Sbill yyerror("Reference to undefined local label %df", i); 395596Sbill lgensym[i] = 1; 396596Sbill genref[i] = 0; 397596Sbill } 398596Sbill } 399596Sbill 400596Sbill pass1_5() 401596Sbill { 402596Sbill sortsymtab(); 403596Sbill #ifdef DEBUG 404596Sbill if (debug) dumpsymtab(); 405596Sbill #endif 406596Sbill jxxxfix(); 407596Sbill #ifdef DEBUG 408596Sbill if (debug) dumpsymtab(); 409596Sbill #endif 410596Sbill } 411596Sbill 412596Sbill open_a_out() 413596Sbill { 414596Sbill /* 415596Sbill * Open up the a.out file now, and get set to build 416596Sbill * up offsets into it for all of the various text,data 417596Sbill * text relocation and data relocation segments. 418596Sbill */ 419596Sbill a_out_file = fopen(outfile, "w"); 420596Sbill if (a_out_file == NULL) { 421596Sbill yyerror("Cannot create %s", outfile); 422596Sbill delexit(); 423596Sbill } 424596Sbill biofd = a_out_file->_file; 425596Sbill a_out_off = 0; 426596Sbill } 427596Sbill 428596Sbill roundsegments() 429596Sbill { 430596Sbill register int locindex; 431596Sbill register long v; 432596Sbill /* 433596Sbill * round and assign text segment origins 434596Sbill * the exec header always goes in usefile[0] 435596Sbill */ 436596Sbill tsize = 0; 437596Sbill for (locindex=0; locindex<NLOC; locindex++) { 438631Shenry v = round(usedot[locindex].e_xvalue, FW); 439631Shenry usedot[locindex].e_xvalue = tsize; 440596Sbill if ((locindex == 0) || (v != 0) ){ 441596Sbill usefile[locindex] = (BFILE *)Calloc(1, sizeof(BFILE)); 442596Sbill bopen(usefile[locindex], a_out_off); 443596Sbill if (locindex == 0) 444596Sbill a_out_off = sizeof (struct exec); 445596Sbill } else { 446596Sbill usefile[locindex] = (BFILE *)-1; 447596Sbill } 448596Sbill tsize += v; 449596Sbill a_out_off += v; 450596Sbill } 451596Sbill /* 452596Sbill * Round and assign data segment origins. 453596Sbill */ 454596Sbill datbase = round(tsize, PAGRND); 455596Sbill for (locindex=0; locindex<NLOC; locindex++) { 456631Shenry v = round(usedot[NLOC+locindex].e_xvalue, FW); 457631Shenry usedot[NLOC+locindex].e_xvalue = datbase + dsize; 458596Sbill if (v != 0){ 459596Sbill usefile[NLOC + locindex] = (BFILE *)Calloc(1,sizeof(BFILE)); 460596Sbill bopen(usefile[NLOC + locindex], a_out_off); 461596Sbill } else { 462596Sbill usefile[NLOC + locindex] = (BFILE *)-1; 463596Sbill } 464596Sbill dsize += v; 465596Sbill a_out_off += v; 466596Sbill } 467596Sbill /* 468596Sbill * Assign final values to symbols 469596Sbill */ 470596Sbill hdr.a_bss = dsize; 471596Sbill freezesymtab(); /* this touches hdr.a_bss */ 472596Sbill stabfix(); 473596Sbill /* 474596Sbill * Set up the relocation information "files" to 475596Sbill * be zero; outrel takes care of the rest 476596Sbill */ 477596Sbill for (locindex = 0; locindex < NLOC + NLOC; locindex++){ 478596Sbill rusefile[locindex] = (struct relbufdesc *)0; 479596Sbill } 480596Sbill } 481596Sbill 482596Sbill build_hdr() 483596Sbill { 484596Sbill /* 485596Sbill * Except for the text and data relocation sizes, 486596Sbill * calculate the final values for the header 487596Sbill * 488596Sbill * Write out the initial copy; we to come 489596Sbill * back later and patch up a_trsize and a_drsize, 490596Sbill * and overwrite this first version of the header. 491596Sbill */ 492596Sbill hdr.a_magic = MAGIC; 493596Sbill hdr.a_text = tsize; 494596Sbill hdr.a_data = dsize; 495596Sbill hdr.a_bss -= dsize; 496596Sbill hdr.a_syms = sizesymtab(); /* Does not include string pool length */ 497596Sbill hdr.a_entry = 0; 498596Sbill hdr.a_trsize = 0; 499596Sbill hdr.a_drsize = 0; 500596Sbill 501596Sbill bwrite((char *)&hdr, sizeof(hdr), usefile[0]); 502596Sbill } 503596Sbill 504596Sbill i_pass2() 505596Sbill { 506596Sbill if (useVM == 0) { 507596Sbill fclose(tmpfil); 508596Sbill tmpfil = fopen(tmpn1, "r"); 509596Sbill if (tmpfil==NULL) { 510596Sbill yyerror("Bad pass 2 temporary file for reading %s", tmpn1); 511596Sbill delexit(); 512596Sbill } 513596Sbill } 514596Sbill } 515596Sbill 516596Sbill pass2() 517596Sbill { 518596Sbill #ifdef DEBUG 519596Sbill if (debug) 520596Sbill printf("\n\n\n\t\tPASS 2\n\n\n\n"); 521596Sbill #endif DEBUG 522596Sbill passno = 2; 523596Sbill lineno = 1; 524596Sbill dotp = &usedot[0]; 525596Sbill txtfil = usefile[0]; /* already opened (always!) */ 526596Sbill relfil = 0; /* outrel takes care of the rest */ 527596Sbill initoutrel(); 528596Sbill 529596Sbill inittmpfile(); 530596Sbill 531596Sbill yyparse(); 532596Sbill 533596Sbill closetmpfile(); 534596Sbill } 535596Sbill 536596Sbill fillsegments() 537596Sbill { 538596Sbill int locindex; 539596Sbill /* 540596Sbill * Round text and data segments to FW by appending zeros 541596Sbill */ 542596Sbill for (locindex = 0; locindex < NLOC + NLOC; locindex++) { 543596Sbill if (usefile[locindex]) { 544596Sbill txtfil = usefile[locindex]; 545596Sbill dotp = &usedot[locindex]; 546631Shenry while (usedot[locindex].e_xvalue & FW) 547596Sbill outb(0); 548596Sbill } 549596Sbill } 550596Sbill } 551596Sbill 552596Sbill reloc_syms() 553596Sbill { 554596Sbill u_long closerelfil(); 555596Sbill /* 556596Sbill * Move the relocation information to a.out 557596Sbill * a_out_off is the offset so far: 558596Sbill * exec + text segments + data segments 559596Sbill */ 560596Sbill relocfile = (BFILE *)Calloc(1,sizeof(BFILE)); 561596Sbill bopen(relocfile, a_out_off); 562596Sbill a_out_off += closeoutrel(relocfile); 563596Sbill 564596Sbill hdr.a_trsize = trsize; 565596Sbill hdr.a_drsize = drsize; 566596Sbill /* 567596Sbill * Output the symbol table 568596Sbill * and if FLEXNAMES is set, the string pool 569596Sbill */ 570596Sbill symwrite(relocfile); 571596Sbill } 572596Sbill 573596Sbill fix_a_out() 574596Sbill { 575596Sbill if (lseek(a_out_file->_file, 0L, 0) < 0) 576596Sbill yyerror("Reposition for header rewrite fails"); 577596Sbill if (write(a_out_file->_file, (char *)&hdr, sizeof (struct exec)) < 0) 578596Sbill yyerror("Rewrite of header fails"); 579596Sbill } 580596Sbill 581596Sbill delexit() 582596Sbill { 583596Sbill delete(); 584596Sbill if (passno == 2){ 585596Sbill unlink(outfile); 586596Sbill } 587596Sbill exit(1); 588596Sbill } 589596Sbill 590596Sbill delete() 591596Sbill { 592596Sbill if (useVM == 0 || tmpn1[0]) 593596Sbill unlink(tmpn1); 594596Sbill } 595596Sbill 596596Sbill sawabort() 597596Sbill { 598596Sbill char *fillinbuffer(); 599596Sbill while (fillinbuffer() != (char *)0) 600596Sbill continue; 601596Sbill delete(); 602596Sbill exit(1); /*although the previous pass will also exit non zero*/ 603596Sbill } 604596Sbill 605596Sbill panic(fmt, a1, a2, a3, a4) 606596Sbill char *fmt; 607596Sbill /*VARARGS 1*/ 608596Sbill { 609596Sbill yyerror("Assembler panic: bad internal data structure."); 610596Sbill yyerror(fmt, a1, a2, a3, a4); 611596Sbill delete(); 612596Sbill abort(); 613596Sbill } 614