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