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