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