/* * Copyright (c) 1982 Regents of the University of California */ #ifndef lint static char sccsid[] = "@(#)asmain.c 4.10 04/17/82"; #endif not lint #include #include #include #include "as.h" #include "assyms.h" #include "asscan.h" #include "asexpr.h" #ifdef UNIX #define unix_lang_name "VAX/UNIX Assembler V04/17/82 4.10" #endif #ifdef VMS #define vms_lang_name "VAX/VMS C Assembler V1.00" #endif VMS /* * variables to manage reading the assembly source files */ char *dotsname; /*the current file name; managed by the parser*/ int lineno; /*current line number; managed by the parser*/ char **innames; /*names of the files being assembled*/ int ninfiles; /*how many interesting files there are*/ /* * Flags settable from the argv process argument list */ int silent = 0; /*don't complain about any errors*/ int savelabels = 0; /*write the labels to the a.out file*/ int d124 = 4; /*default allocate 4 bytes for unknown pointers*/ int anyerrs = 0; /*no errors yet*/ int anywarnings=0; /*no warnings yet*/ int orgwarn = 0; /*Bad origins*/ int passno = 1; /* current pass*/ int jxxxJUMP = 0; /* in jxxxes that branch too far, use jmp instead of brw */ int readonlydata = 0; /* initialzed data -> text space */ int nGHnumbers = 0; /* GH numbers used */ int nGHopcodes = 0; /* GH opcodes used */ int nnewopcodes = 0; /* new opcodes used */ #ifdef DEBUG int debug = 0; int toktrace = 0; #endif int useVM = /*put the temp file in virtual memory*/ #ifdef VMS 1; /*VMS has virtual memory (duh)*/ #endif VMS #ifdef UNIX 0; #endif char *endcore; /*where to get more symbol space*/ /* * Managers of the a.out file. */ struct exec hdr; #define MAGIC 0407 u_long tsize; /* total text size */ u_long dsize; /* total data size */ u_long datbase; /* base of the data segment */ u_long trsize; /* total text relocation size */ u_long drsize; /* total data relocation size */ /* * Information about the current segment is accumulated in * usedot; the most important information stored is the * accumulated size of each of the text and data segments * * dotp points to the correct usedot expression for the current segment */ struct exp usedot[NLOC+NLOC]; /* info about all segments */ struct exp *dotp; /* data/text location pointer */ /* * The inter pass temporary file is opened and closed by stdio, but * is written to using direct read/write, as the temporary file * is composed of buffers exactly BUFSIZ long. */ FILE *tmpfil; /* interpass communication file */ /* * a.out is created during the second pass. * It is opened by stdio, but is filled with the parallel * block I/O library */ char *outfile = "a.out"; FILE *a_out_file; off_t a_out_off; /* cumulative offsets for segments */ /* * The logical files containing the assembled data for each of * the text and data segments are * managed by the parallel block I/O library. * a.out is logically opened in many places at once to * receive the assembled data from the various segments as * it all trickles in, but is physically opened only once * to minimize file overhead. */ BFILE *usefile[NLOC+NLOC]; /* text/data files */ BFILE *txtfil; /* current text/data file */ /* * Relocation information is accumulated seperately for each * segment. This is required by the old loader (from BTL), * but not by the new loader (Bill Joy). * * However, the size of the relocation information can not be computed * during or after the 1st pass because the ''absoluteness' of values * is unknown until all locally declared symbols have been seen. * Thus, the size of the relocation information is only * known after the second pass is finished. * This obviates the use of the block I/O * library, which requires knowing the exact offsets in a.out. * * So, we save the relocation information internally (we don't * go to internal files to minimize overhead). * * Empirically, we studied 259 files composing the system, * two compilers and a compiler generator: (all of which have * fairly large source files) * * Number of files = 259 * Number of non zero text reloc files: 233 * Number of non zero data reloc files: 53 * Average text relocation = 889 * Average data relocation = 346 * Number of files > BUFSIZ text relocation = 71 * Number of files > BUFSIZ data relocation = 6 * * For compiled C code, there is usually one text segment and two * data segments; we see that allocating our own buffers and * doing our internal handling of relocation information will, * on the average, not use more memory than taken up by the buffers * allocated for doing file I/O in parallel to a number of file. * * If we are assembling with the -V option, we * use the left over token buffers from the 2nd pass, * otherwise, we create our own. * * When the 2nd pass is complete, closeoutrel flushes the token * buffers out to a BFILE. * * The internals to relbufdesc are known only in assyms.c * * outrel constructs the relocation information. * closeoutrel flushes the relocation information to relfil. */ struct relbufdesc *rusefile[NLOC+NLOC]; struct relbufdesc *relfil; /* un concatnated relocation info */ BFILE *relocfile; /* concatnated relocation info */ /* * Once the relocation information has been written, * we can write out the symbol table using the Block I/O * mechanisms, as we once again know the offsets into * the a.out file. * * We use relfil to output the symbol table information. */ char *tmpdirprefix = #ifdef UNIX "/tmp/"; #else VMS "/usr/tmp/"; #endif #define TMP_SUFFIX "asXXXXXX" char tmpn1[TNAMESIZE]; int delexit(); main(argc, argv) int argc; char **argv; { char *sbrk(); tmpn1[0] = 0; endcore = sbrk(0); argprocess(argc, argv); /* process argument lists */ if (anyerrs) exit(1); initialize(); zeroorigins(); /* set origins to zero */ zerolocals(); /* fix local label counters */ i_pass1(); /* open temp files, etc */ pass1(); /* first pass through .s files */ testlocals(); /* check for undefined locals */ if (anyerrs) delexit(); pass1_5(); /* resolve jxxx */ if (anyerrs) delexit(); open_a_out(); /* open a.out */ roundsegments(); /* round segments to FW */ build_hdr(); /* build initial header, and output */ i_pass2(); /* reopen temporary file, etc */ pass2(); /* second pass through the virtual .s */ if (anyerrs) delexit(); fillsegments(); /* fill segments with 0 to FW */ reloc_syms(); /* dump relocation and symbol table */ delete(); /* remove tmp file */ bflush(); /* close off block I/O view of a.out */ fix_a_out(); /* add in text and data reloc counts */ if (anyerrs == 0 && orgwarn) yyerror("Caution: absolute origins.\n"); if (nGHnumbers) yywarning("Caution: G or H format floating point numbers"); if (nGHopcodes) yywarning("Caution: G or H format floating point operators"); if (nnewopcodes) yywarning("Caution: New Opcodes"); if (nGHnumbers || nGHopcodes || nnewopcodes) yywarning("These are not defined for all implementations of the VAX architecture.\n"); exit(anyerrs != 0); } /*end of UNIX main*/ argprocess(argc, argv) int argc; char *argv[]; { register char *cp; ninfiles = 0; silent = 0; #ifdef DEBUG debug = 0; #endif innames = (char **)ClearCalloc(argc+1, sizeof (innames[0])); dotsname = ""; while (argc > 1) { if (argv[1][0] != '-') innames[ninfiles++] = argv[1]; else { cp = argv[1] + 1; /* * We can throw away single minus signs, so * that make scripts for the PDP 11 assembler work * on this assembler too */ while (*cp){ switch(*cp++){ default: yyerror("Unknown flag: %c", *--cp); cp++; break; case 'v': selfwhat(stdout); exit(1); case 'd': d124 = *cp++ - '0'; if ( (d124 != 1) && (d124 != 2) && (d124 != 4)){ yyerror("-d[124] only"); exit(1); } break; case 'o': if (argc < 3){ yyerror("-o what???"); exit(1); } outfile = argv[2]; bumpone: argc -= 2; argv += 2; goto nextarg; case 't': if (argc < 3){ yyerror("-t what???"); exit(1); } tmpdirprefix = argv[2]; goto bumpone; case 'V': useVM = 1; break; case 'W': silent = 1; break; case 'L': savelabels = 1; break; case 'J': jxxxJUMP = 1; break; #ifdef DEBUG case 'D': debug = 1; break; case 'T': toktrace = 1; break; #endif case 'R': readonlydata = 1; break; } /*end of the switch*/ } /*end of pulling out all arguments*/ } /*end of a flag argument*/ --argc; ++argv; nextarg:; } /* innames[ninfiles] = 0; */ } /* * poke through the data space and find all sccs identifiers. * We assume: * a) that extern char **environ; is the first thing in the bss * segment (true, if one is using the new version of cmgt.crt0.c) * b) that the sccsid's have not been put into text space. */ selfwhat(place) FILE *place; { extern char **environ; register char *ub; register char *cp; register char *pat; char *sbrk(); for (cp = (char *)&environ, ub = sbrk(0); cp < ub; cp++){ if (cp[0] != '@') continue; if (cp[1] != '(') continue; if (cp[2] != '#') continue; if (cp[3] != ')') continue; fputc('\t', place); for (cp += 4; cp < ub; cp++){ if (*cp == 0) break; if (*cp == '>') break; if (*cp == '\n') break; fputc(*cp, place); } fputc('\n', place); } } initialize() { if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, delexit); /* * Install symbols in the table */ symtabinit(); syminstall(); /* * Build the expression parser accelerator token sets */ buildtokensets(); } zeroorigins() { register int locindex; /* * Mark usedot: the first NLOC slots are for named text segments, * the next for named data segments. */ for (locindex = 0; locindex < NLOC; locindex++){ usedot[locindex].e_xtype = XTEXT; usedot[NLOC + locindex].e_xtype = XDATA; usedot[locindex].e_xvalue = 0; usedot[NLOC + locindex].e_xvalue = 0; } } zerolocals() { register int i; for (i = 0; i <= 9; i++) { lgensym[i] = 1; genref[i] = 0; } } i_pass1() { if (useVM == 0){ strcat(tmpn1, tmpdirprefix); if (tmpdirprefix[strlen(tmpdirprefix)-1] != '/') strcat(tmpn1, "/"); (void)strcat(tmpn1, TMP_SUFFIX); (void)mktemp(tmpn1); tmpfil = fopen(tmpn1, "w"); if (tmpfil==NULL) { yyerror("Bad pass 1 temporary file for writing %s", tmpn1); delexit(); } } inittmpfile(); initijxxx(); } pass1() { register int i; passno = 1; dotp = &usedot[0]; txtfil = (BFILE *)0; relfil = (struct relbufdesc *)0; if (ninfiles == 0){ /*take the input from stdin directly*/ lineno = 1; dotsname = ""; yyparse(); } else { /*we have the names tanked*/ for (i = 0; i < ninfiles; i++){ new_dot_s(innames[i]); if (freopen(innames[i], "r", stdin) == NULL) { yyerror( "Can't open source file %s\n", innames[i]); exit(2); } /* stdio is NOT used to read the input characters */ /* we use read directly, into our own buffers */ yyparse(); } } closetmpfile(); /*kick out the last buffered intermediate text*/ } testlocals() { register int i; for (i = 0; i <= 9; i++) { if (genref[i]) yyerror("Reference to undefined local label %df", i); lgensym[i] = 1; genref[i] = 0; } } pass1_5() { sortsymtab(); #ifdef DEBUG if (debug) dumpsymtab(); #endif jxxxfix(); #ifdef DEBUG if (debug) dumpsymtab(); #endif } open_a_out() { /* * Open up the a.out file now, and get set to build * up offsets into it for all of the various text,data * text relocation and data relocation segments. */ a_out_file = fopen(outfile, "w"); if (a_out_file == NULL) { yyerror("Cannot create %s", outfile); delexit(); } biofd = a_out_file->_file; a_out_off = 0; } roundsegments() { register int locindex; register long v; /* * round and assign text segment origins * the exec header always goes in usefile[0] */ tsize = 0; for (locindex=0; locindex_file, 0L, 0) < 0L) yyerror("Reposition for header rewrite fails"); if (write(a_out_file->_file, (char *)&hdr, sizeof (struct exec)) < 0) yyerror("Rewrite of header fails"); } delexit() { delete(); if (passno == 2){ unlink(outfile); } exit(1); } delete() { if (useVM == 0 || tmpn1[0]) unlink(tmpn1); } sawabort() { char *fillinbuffer(); while (fillinbuffer() != (char *)0) continue; delete(); exit(1); /*although the previous pass will also exit non zero*/ } panic(fmt, a1, a2, a3, a4) char *fmt; /*VARARGS 1*/ { yyerror("Assembler panic: bad internal data structure."); yyerror(fmt, a1, a2, a3, a4); delete(); abort(); }