/* * Copyright (c) 1982 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #ifndef lint char copyright[] = "@(#) Copyright (c) 1982 Regents of the University of California.\n\ All rights reserved.\n"; #endif not lint #ifndef lint static char sccsid[] = "@(#)asmain.c 5.2 (Berkeley) 10/21/85"; #endif not lint #include #include #include #include "as.h" #include "assyms.h" #include "asscan.h" #include "asexpr.h" #include #define unix_lang_name "VAX/UNIX Assembler V10/21/85 5.2" /* * 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 maxalign = 2; /*default .align maximum*/ 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 = 0; 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 token 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 *tokfile; /* interpass communication file */ char tokfilename[TNAMESIZE]; /* * The string file is the string table * cat'ed to the end of the built up a.out file */ FILE *strfile; /* interpass string file */ char strfilename[TNAMESIZE]; int strfilepos = 0; /* position within the string 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 = "/tmp/"; int delexit(); main(argc, argv) int argc; char **argv; { char *sbrk(); tokfilename[0] = 0; strfilename[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); } 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 'a': maxalign = atoi(cp+1); for (cp++; isdigit(*cp); cp++) /*VOID*/; if ( (maxalign > 16) || (maxalign < 0)){ yyerror("-a: 0<=align<=16"); 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() { FILE *tempopen(); if (useVM == 0) tokfile = tempopen(tokfilename, "T"); strfile = tempopen(strfilename, "S"); /* * write out the string length. * This will be overwritten when the * strings are tacked onto the growing a.out file */ strfilepos = sizeof(int); fwrite(&strfilepos, sizeof(int), 1, strfile); inittokfile(); initijxxx(); } FILE *tempopen(tname, part) char *tname; char *part; { FILE *file; sprintf(tname, "%s%sas%s%05d", tmpdirprefix, (tmpdirprefix[strlen(tmpdirprefix)-1] != '/') ? "/" : "", part, getpid()); file = fopen(tname, "w"); if (file == NULL) { yyerror("Bad pass 1 temporary file for writing %s", tname); delexit(); } return(file); } 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(); } } closetokfile(); /*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() { struct stat stb; /* * 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; fstat(biofd, &stb); biobufsize = stb.st_blksize; 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 || tokfilename[0]) unlink(tokfilename); if (strfilename[0]) unlink(strfilename); } 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(); }