/* * lcode.c -- linker routines to parse .u1 files and produce icode. */ #include #include "..\h\config.h" #include "general.h" #include "tproto.h" #include "globals.h" #include "opcode.h" #include "link.h" #include "..\h\keyword.h" #include "..\h\version.h" #include "..\h\header.h" /* * Prototypes. */ hidden novalue backpatch Params((int lab)); hidden novalue clearlab Params((noargs)); hidden novalue flushcode Params((noargs)); hidden novalue intout Params((int oint)); hidden novalue lemit Params((int op,char *name)); hidden novalue lemitcon Params((int k)); hidden novalue lemiteven Params((noargs)); hidden novalue lemitin Params((int op,word offset,int n,char *name)); hidden novalue lemitint Params((int op,long i,char *name)); hidden novalue lemitl Params((int op,int lab,char *name)); hidden novalue lemitn Params((int op,word n,char *name)); hidden novalue lemitproc Params((char *name,int nargs,int ndyn,int nstat, int fstat)); hidden novalue lemitr Params((int op,word loc,char *name)); hidden novalue outblock Params((char *addr,int count)); hidden novalue wordout Params((word oword)); #ifdef DeBugLinker hidden novalue dumpblock Params((char *addr,int count)); #endif /* DeBugLinker */ #if AMIGA #include #endif /* AMIGA */ #if MVS extern char *routname; /* at least under SAS C */ #endif /* MVS */ #ifndef MaxHeader #define MaxHeader MaxHdr #endif /* MaxHeader */ word pc = 0; /* simulated program counter */ #define outword(n) wordout((word)(n)) #define outop(n) intout((int)(n)) #define CodeCheck(n) if ((long)codep + n > (long)((long)codeb + maxcode))\ quit("out of code buffer space") /* * gencode - read .u1 file, resolve variable references, and generate icode. * Basic process is to read each line in the file and take some action * as dictated by the opcode. This action sometimes involves parsing * of arguments and usually culminates in the call of the appropriate * lemit* routine. */ novalue gencode() { register int op, k, lab; int j, nargs, flags, implicit; char *id, *name, *procname; struct centry *cp; struct gentry *gp; struct fentry *fp; union xval gg; while ((op = getopc(&name)) != EOF) { switch (op) { /* Ternary operators. */ case Op_Toby: case Op_Sect: /* Binary operators. */ case Op_Asgn: case Op_Cat: case Op_Diff: case Op_Div: case Op_Eqv: case Op_Inter: case Op_Lconcat: case Op_Lexeq: case Op_Lexge: case Op_Lexgt: case Op_Lexle: case Op_Lexlt: case Op_Lexne: case Op_Minus: case Op_Mod: case Op_Mult: case Op_Neqv: case Op_Numeq: case Op_Numge: case Op_Numgt: case Op_Numle: case Op_Numlt: case Op_Numne: case Op_Plus: case Op_Power: case Op_Rasgn: case Op_Rswap: case Op_Subsc: case Op_Swap: case Op_Unions: /* Unary operators. */ case Op_Bang: case Op_Compl: case Op_Neg: case Op_Nonnull: case Op_Null: case Op_Number: case Op_Random: case Op_Refresh: case Op_Size: case Op_Tabmat: case Op_Value: /* Instructions. */ case Op_Bscan: case Op_Ccase: case Op_Coact: case Op_Cofail: case Op_Coret: case Op_Dup: case Op_Efail: case Op_Eret: case Op_Escan: case Op_Esusp: case Op_Limit: case Op_Lsusp: case Op_Pfail: case Op_Pnull: case Op_Pop: case Op_Pret: case Op_Psusp: case Op_Push1: case Op_Pushn1: case Op_Sdup: newline(); lemit(op, name); break; case Op_Chfail: case Op_Create: case Op_Goto: case Op_Init: lab = getlab(); newline(); lemitl(op, lab, name); break; case Op_Cset: case Op_Real: k = getdec(); newline(); lemitr(op, lctable[k].c_pc, name); break; case Op_Field: id = getid(); newline(); fp = flocate(id); if (fp == NULL) { lfatal(id, "invalid field name"); break; } lemitn(op, (word)(fp->f_fid-1), name); break; case Op_Int: { long i; k = getdec(); newline(); cp = &lctable[k]; /* * Check to see if a large integers has been converted to a string. * If so, generate the code for +s. */ if (cp->c_flag & F_StrLit) { id = cp->c_val.sval; lemit(Op_Pnull,"pnull"); lemitin(Op_Str, (word)(id-lsspace), cp->c_length, "str"); lemit(Op_Number,"number"); break; } i = (long)cp->c_val.ival; lemitint(op, i, name); break; } case Op_Invoke: k = getdec(); newline(); if (k == -1) lemit(Op_Apply,"apply"); else lemitn(op, (word)k, name); break; case Op_Keywd: k = getdec(); newline(); switch (k) { case K_FAIL: lemit(Op_Efail,"efail"); break; case K_NULL: lemit(Op_Pnull,"pnull"); break; default: lemitn(op, (word)k, name); } break; case Op_Llist: k = getdec(); newline(); lemitn(op, (word)k, name); break; case Op_Lab: lab = getlab(); newline(); #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "L%d:\n", lab); #endif /* DeBugLinker */ backpatch(lab); break; case Op_Line: if (lnfree >= &lntable[nsize]) quit("out of line number table space"); lnfree->ipc = pc; lineno = getdec(); lnfree->line = lineno; lnfree++; #ifdef EvalTrace lemitn(op, (word)lineno, name); #endif /* EvalTrace */ newline(); #ifdef LineCodes lemit(Op_Noop,"noop"); #endif /* LineCodes */ break; #ifdef EvalTrace case Op_Colm: colmno = getdec(); lemitn(op, (word)colmno, name); break; #endif /* EvalTrace */ case Op_Mark: lab = getlab(); newline(); lemitl(op, lab, name); break; case Op_Mark0: lemit(op, name); break; case Op_Str: k = getdec(); newline(); cp = &lctable[k]; id = cp->c_val.sval; lemitin(op, (word)(id-lsspace), cp->c_length, name); break; case Op_Tally: k = getdec(); newline(); lemitn(op, (word)k, name); break; case Op_Unmark: lemit(Op_Unmark, name); break; case Op_Var: k = getdec(); newline(); flags = lltable[k].l_flag; if (flags & F_Global) lemitn(Op_Global, (word)(lltable[k].l_val.global-lgtable), "global"); else if (flags & F_Static) lemitn(Op_Static, (word)(lltable[k].l_val.staticid-1), "static"); else if (flags & F_Argument) lemitn(Op_Arg, (word)(lltable[k].l_val.offset-1), "arg"); else lemitn(Op_Local, (word)(lltable[k].l_val.offset-1), "local"); break; /* Declarations. */ case Op_Proc: procname = getid(); newline(); locinit(); clearlab(); lineno = 0; gp = glocate(procname); implicit = gp->g_flag & F_ImpError; nargs = gp->g_nargs; lemiteven(); break; case Op_Local: k = getdec(); flags = getoct(); id = getid(); putlocal(k, id, flags, implicit, procname); break; case Op_Con: k = getdec(); flags = getoct(); if (flags & F_IntLit) { { long m; char *s; j = getdec(); /* number of characters in integer */ m = getint(j,&s); /* convert if possible */ if (m < 0) { /* negative indicates integer too big */ gg.sval = s; /* convert to a string */ putconst(k, F_StrLit, j, pc, &gg); } else { /* integers is small enough */ gg.ival = m; putconst(k, flags, 0, pc, &gg); } } } else if (flags & F_RealLit) { gg.rval = getreal(); putconst(k, flags, 0, pc, &gg); } else if (flags & F_StrLit) { j = getdec(); gg.sval = getstrlit(j); putconst(k, flags, j, pc, &gg); } else if (flags & F_CsetLit) { j = getdec(); gg.sval = getstrlit(j); putconst(k, flags, j, pc, &gg); } else fprintf(stderr, "gencode: illegal constant\n"); newline(); lemitcon(k); break; case Op_Filen: if (fnmfree >= &fnmtbl[fnmsize]) quit("out of file name table space"); #ifdef CRAY fnmfree->ipc = pc/8; #else /* CRAY */ fnmfree->ipc = pc; #endif /* CRAY */ fnmfree->fname = getrest() - lsspace; fnmfree++; newline(); break; case Op_Declend: newline(); gp->g_pc = pc; lemitproc(procname, nargs, dynoff, lstatics-static1, static1); break; case Op_End: newline(); flushcode(); break; default: fprintf(stderr, "gencode: illegal opcode(%d): %s\n", op, name); newline(); } } } /* * lemit - emit opcode. * lemitl - emit opcode with reference to program label. * for a description of the chaining and backpatching for labels. * lemitn - emit opcode with integer argument. * lemitr - emit opcode with pc-relative reference. * lemitin - emit opcode with reference to identifier table & integer argument. * lemitint - emit word opcode with integer argument. * lemiteven - emit null bytes to bring pc to word boundary. * lemitcon - emit constant table entry. * lemitproc - emit procedure block. * * The lemit* routines call out* routines to effect the "outputting" of icode. * Note that the majority of the code for the lemit* routines is for debugging * purposes. */ static novalue lemit(op, name) int op; char *name; { #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "%ld:\t%d\t\t\t\t# %s\n", (long)pc, op, name); #else /* DeBugLinker */ #if MACINTOSH && MPW /* #pragma unused(name) */ #endif /* MACINTOSH && MPW */ #endif /* DeBugLinker */ outop(op); } static novalue lemitl(op, lab, name) int op, lab; char *name; { #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "%ld:\t%d\tL%d\t\t\t# %s\n", (long)pc, op, lab, name); #else /* DeBugLinker */ #if MACINTOSH && MPW /* #pragma unused(name) */ #endif /* MACINTOSH && MPW */ #endif /* DeBugLinker */ if (lab >= maxlabels) quit("out of label space"); outop(op); if (labels[lab] <= 0) { /* forward reference */ outword(labels[lab]); labels[lab] = WordSize - pc; /* add to front of reference chain */ } else /* output relative offset */ #ifdef CRAY outword((labels[lab] - (pc + WordSize))/8); #else /* CRAY */ outword(labels[lab] - (pc + WordSize)); #endif /* CRAY */ } static novalue lemitn(op, n, name) int op; word n; char *name; { #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "%ld:\t%d\t%ld\t\t\t# %s\n", (long)pc, op, (long)n, name); #else /* DeBugLinker */ #if MACINTOSH && MPW /* #pragma unused(name) */ #endif /* MACINTOSH && MPW */ #endif /* DeBugLinker */ outop(op); outword(n); } static novalue lemitr(op, loc, name) int op; word loc; char *name; { #ifdef CRAY loc = (loc - pc - 16)/8; #else /* CRAY */ loc -= pc + ((IntBits/ByteBits) + WordSize); #endif /* CRAY */ #ifdef DeBugLinker if (Dflag) { if (loc >= 0) fprintf(dbgfile, "%ld:\t%d\t*+%ld\t\t\t# %s\n",(long) pc, op, (long)loc, name); else fprintf(dbgfile, "%ld:\t%d\t*-%ld\t\t\t# %s\n",(long) pc, op, (long)-loc, name); } #else /* DeBugLinker */ #if MACINTOSH && MPW /* #pragma unused(name) */ #endif /* MACINTOSH && MPW */ #endif /* DeBugLinker */ outop(op); outword(loc); } static novalue lemitin(op, offset, n, name) int op, n; word offset; char *name; { #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "%ld:\t%d\t%d,I+%ld\t\t\t# %s\n", (long)pc, op, n, (long)offset, name); #else /* DeBugLinker */ #if MACINTOSH && MPW /* #pragma unused(name) */ #endif /* MACINTOSH && MPW */ #endif /* DeBugLinker */ outop(op); outword(n); outword(offset); } /* * lemitint can have some pitfalls. outword is used to output the * integer and this is picked up in the interpreter as the second * word of a short integer. The integer value output must be * the same size as what the interpreter expects. See op_int and op_intx * in interp.s */ static novalue lemitint(op, i, name) int op; long i; char *name; { #ifdef DeBugLinker if (Dflag) fprintf(dbgfile,"%ld:\t%d\t%ld\t\t\t# %s\n",(long)pc,op,(long)i,name); #else /* DeBugLinker */ #if MACINTOSH && MPW /* #pragma unused(name) */ #endif /* MACINTOSH && MPW */ #endif /* DeBugLinker */ outop(op); outword(i); } static novalue lemiteven() { word x = 0; register int len; if (len = pc % (IntBits/ByteBits)) outblock((char *)x, (IntBits/ByteBits) - len); } static novalue lemitcon(k) register int k; { register int i, j; register char *s; int csbuf[CsetSize]; union { char ovly[1]; /* Array used to overlay l and f on a bytewise basis. */ long l; double f; } x; if (lctable[k].c_flag & F_RealLit) { #ifdef Double /* access real values one word at a time */ { int *rp, *rq; rp = (int *) &(x.f); rq = (int *) &(lctable[k].c_val.rval); *rp++ = *rq++; *rp = *rq; } #else /* Double */ x.f = lctable[k].c_val.rval; #endif /* Double */ #ifdef DeBugLinker if (Dflag) { fprintf(dbgfile, "%ld:\t%d\n", (long)pc, T_Real); dumpblock(x.ovly,sizeof(double)); fprintf(dbgfile, "\t\t\t( %g )\n",x.f); } #endif /* DeBugLinker */ outword(T_Real); #ifdef Double /* fill out real block with an empty word */ outword(0); #endif /* Double */ outblock(x.ovly,sizeof(double)); } else if (lctable[k].c_flag & F_CsetLit) { for (i = 0; i < CsetSize; i++) csbuf[i] = 0; s = lctable[k].c_val.sval; i = lctable[k].c_length; while (i--) { Setb(ToAscii(*s), csbuf); s++; } j = 0; for (i = 0; i < 256; i++) { if (Testb(i, csbuf)) j++; } #ifdef DeBugLinker if (Dflag) { fprintf(dbgfile, "%ld:\t%d\n",(long) pc, T_Cset); fprintf(dbgfile, "\t%d\n",j); } #endif /* DeBugLinker */ outword(T_Cset); outword(j); /* cset size */ outblock((char *)csbuf,sizeof(csbuf)); #ifdef DeBugLinker if (Dflag) dumpblock((char *)csbuf,CsetSize); #endif /* DeBugLinker */ } } static novalue lemitproc(name, nargs, ndyn, nstat, fstat) char *name; int nargs, ndyn, nstat, fstat; { register int i; register char *p; int size; /* * FncBlockSize = sizeof(BasicFncBlock) + * sizeof(descrip)*(# of args + # of dynamics + # of statics). */ size = (9*WordSize) + (2*WordSize) * (abs(nargs)+ndyn+nstat); #ifdef DeBugLinker if (Dflag) { fprintf(dbgfile, "%ld:\t%d\n", (long)pc, T_Proc); /* type code */ fprintf(dbgfile, "\t%d\n", size); /* size of block */ fprintf(dbgfile, "\tZ+%ld\n",(long)(pc+size)); /* entry point */ fprintf(dbgfile, "\t%d\n", nargs); /* # arguments */ fprintf(dbgfile, "\t%d\n", ndyn); /* # dynamic locals */ fprintf(dbgfile, "\t%d\n", nstat); /* # static locals */ fprintf(dbgfile, "\t%d\n", fstat); /* first static */ fprintf(dbgfile, "\t%d\tI+%ld\t\t\t# %s\n", /* name of procedure */ (int)strlen(name), (long)(name-lsspace), name); } #endif /* DeBugLinker */ outword(T_Proc); outword(size); outword(pc + size - 2*WordSize); /* Have to allow for the two words that we've already output. */ outword(nargs); outword(ndyn); outword(nstat); outword(fstat); outword(strlen(name)); outword(name - lsspace); /* * Output string descriptors for argument names by looping through * all locals, and picking out those with F_Argument set. */ for (i = 0; i <= nlocal; i++) { if (lltable[i].l_flag & F_Argument) { p = lltable[i].l_name; #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "\t%d\tI+%ld\t\t\t# %s\n", (int)strlen(p), (long)(p-lsspace), p); #endif /* DeBugLinker */ outword(strlen(p)); outword(p - lsspace); } } /* * Output string descriptors for local variable names. */ for (i = 0; i <= nlocal; i++) { if (lltable[i].l_flag & F_Dynamic) { p = lltable[i].l_name; #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "\t%d\tI+%ld\t\t\t# %s\n", (int)strlen(p), (long)(p-lsspace), p); #endif /* DeBugLinker */ outword(strlen(p)); outword(p - lsspace); } } /* * Output string descriptors for local variable names. */ for (i = 0; i <= nlocal; i++) { if (lltable[i].l_flag & F_Static) { p = lltable[i].l_name; #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "\t%d\tI+%ld\t\t\t# %s\n", (int)strlen(p), (long)(p-lsspace), p); #endif /* DeBugLinker */ outword(strlen(p)); outword(p - lsspace); } } } /* * gentables - generate interpreter code for global, static, * identifier, and record tables, and built-in procedure blocks. */ novalue gentables() { register int i; register char *s; register struct gentry *gp; struct fentry *fp; struct rentry *rp; struct header hdr; #if MVS FILE *toutfile; /* temporary file for icode output */ #endif /* MVS */ lemiteven(); /* * Output record constructor procedure blocks. */ hdr.records = pc; #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "%ld:\t%d\t\t\t\t# record blocks\n",(long)pc, nrecords); #endif /* DeBugLinker */ outword(nrecords); for (gp = lgtable; gp < lgfree; gp++) { if (gp->g_flag & (F_Record & ~F_Global)) { s = gp->g_name; gp->g_pc = pc; #ifdef DeBugLinker if (Dflag) { fprintf(dbgfile, "%ld:\n", pc); fprintf(dbgfile, "\t%d\n", T_Proc); fprintf(dbgfile, "\t%d\n", RkBlkSize); fprintf(dbgfile, "\t_mkrec\n"); fprintf(dbgfile, "\t%d\n", gp->g_nargs); fprintf(dbgfile, "\t-2\n"); fprintf(dbgfile, "\t%d\n", gp->g_procid); fprintf(dbgfile, "\t1\n"); fprintf(dbgfile, "\t%d\tI+%ld\t\t\t# %s\n", (int)strlen(s), (long)(s-lsspace), s); } #endif /* DeBugLinker */ outword(T_Proc); /* type code */ outword(RkBlkSize); /* size of block */ outword(0); /* entry point (filled in by interp)*/ outword(gp->g_nargs); /* number of fields */ outword(-2); /* record constructor indicator */ outword(gp->g_procid); /* record id */ outword(1); /* serial number */ outword(strlen(s)); /* name of record */ outword(s - lsspace); } } /* * Output record/field table. */ hdr.ftab = pc; #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "%ld:\t\t\t\t\t# record/field table\n", (long)pc); #endif /* DeBugLinker */ for (fp = lftable; fp < lffree; fp++) { #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "%ld:\n", (long)pc); #endif /* DeBugLinker */ rp = fp->f_rlist; for (i = 1; i <= nrecords; i++) { if (rp != NULL && rp->r_recid == i) { #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "\t%d\n", rp->r_fnum); #endif /* DeBugLinker */ outword(rp->r_fnum); rp = rp->r_link; } else { #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "\t-1\n"); #endif /* DeBugLinker */ outword(-1); } #ifdef DeBugLinker if (Dflag && (i == nrecords || (i & 03) == 0)) putc('\n', dbgfile); #endif /* DeBugLinker */ } } /* * Output descriptors for field names. */ hdr.fnames = pc; for (fp = lftable; fp < lffree; fp++) { s = fp->f_name; #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "%ld:\t%d\tI+%ld\t\t\t# %s\n", (long)pc, (int)strlen(s), (long)(s-lsspace), s); #endif /* DeBugLinker */ outword(strlen(s)); /* name of field */ outword(s - lsspace); } /* * Output global variable descriptors. */ hdr.globals = pc; for (gp = lgtable; gp < lgfree; gp++) { if (gp->g_flag & (F_Builtin & ~F_Global)) { /* function */ #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "%ld:\t%06lo\t%d\t\t\t# %s\n", (long)pc, (long)D_Proc, -gp->g_procid, gp->g_name); #endif /* DeBugLinker */ outword(D_Proc); outword(-gp->g_procid); } else if (gp->g_flag & (F_Proc & ~F_Global)) { /* Icon procedure */ #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "%ld:\t%06lo\tZ+%ld\t\t\t# %s\n", (long)pc,(long)D_Proc, (long)gp->g_pc, gp->g_name); #endif /* DeBugLinker */ outword(D_Proc); outword(gp->g_pc); } else if (gp->g_flag & (F_Record & ~F_Global)) { /* record constructor */ #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "%ld:\t%06lo\tZ+%ld\t\t\t# %s\n", (long)pc, (long)D_Proc, (long)gp->g_pc, gp->g_name); #endif /* DeBugLinker */ outword(D_Proc); outword(gp->g_pc); } else { /* global variable */ #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "%ld:\t%06lo\t0\t\t\t# %s\n",(long)pc, (long)D_Null, gp->g_name); #endif /* DeBugLinker */ outword(D_Null); outword(0); } } /* * Output descriptors for global variable names. */ hdr.gnames = pc; for (gp = lgtable; gp < lgfree; gp++) { #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "%ld:\t%d\tI+%ld\t\t\t# %s\n", (long)pc, (int)strlen(gp->g_name), (long)(gp->g_name-lsspace), gp->g_name); #endif /* DeBugLinker */ outword(strlen(gp->g_name)); outword(gp->g_name - lsspace); } /* * Output a null descriptor for each static variable. */ hdr.statics = pc; for (i = lstatics; i > 0; i--) { #ifdef DeBugLinker if (Dflag) fprintf(dbgfile, "%ld:\t0\t0\n", (long)pc); #endif /* DeBugLinker */ outword(D_Null); outword(0); } flushcode(); /* * Output the string constant table and the two tables associating icode * locations with source program locations. Note that the calls to write * really do all the work. */ #ifdef DeBugLinker if (Dflag) { for (s = lsspace; s < lsfree; ) { fprintf(dbgfile, "%ld:\t%03o", (long)pc, *s++); for (i = 7; i > 0; i--) { if (s >= lsfree) break; fprintf(dbgfile, " %03o", *s++); } putc('\n', dbgfile); } } #endif /* DeBugLinker */ hdr.filenms = pc; pc += (char *)fnmfree - (char *)fnmtbl; hdr.linenums = pc; pc += (char *)lnfree - (char *)lntable; hdr.strcons = pc; pc += lsfree - lsspace; if (longwrite((char *)fnmtbl, (long)((char *)fnmfree - (char *)fnmtbl), outfile) < 0) quit("cannot write icode file"); if (longwrite((char *)lntable, (long)((char *)lnfree - (char *)lntable), outfile) < 0) quit("cannot write icode file"); if (longwrite(lsspace, (long)(lsfree - lsspace), outfile) < 0) quit("cannot write icode file"); /* * Output icode file header. */ hdr.hsize = pc; strcpy((char *)hdr.config,IVersion); hdr.trace = trace; #ifdef DeBugLinker if (Dflag) { fprintf(dbgfile, "size: %ld\n", (long)hdr.hsize); fprintf(dbgfile, "trace: %ld\n", (long)hdr.trace); fprintf(dbgfile, "records: %ld\n", (long)hdr.records); fprintf(dbgfile, "ftab: %ld\n", (long)hdr.ftab); fprintf(dbgfile, "fnames: %ld\n", (long)hdr.fnames); fprintf(dbgfile, "globals: %ld\n", (long)hdr.globals); fprintf(dbgfile, "gnames: %ld\n", (long)hdr.gnames); fprintf(dbgfile, "statics: %ld\n", (long)hdr.statics); fprintf(dbgfile, "strcons: %ld\n", (long)hdr.strcons); fprintf(dbgfile, "filenms: %ld\n", (long)hdr.filenms); fprintf(dbgfile, "linenums: %ld\n", (long)hdr.linenums); fprintf(dbgfile, "config: %s\n", hdr.config); } #endif /* DeBugLinker */ #ifdef Header fseek(outfile, (long)MaxHeader, 0); #else /* Header */ #if MVS /* * This kind of backpatching cannot work on a PDS member, and that's * probably where the code is going. So the code goes out first to * a temporary file, and then copied to the real icode file after * the header is written. */ fseek(outfile, sizeof(hdr), SEEK_SET); toutfile = outfile; outfile = fopen(routname, WriteBinary); if (outfile == NULL) quitf("cannot create %s",routname); #else fseek(outfile, 0L, 0); #endif /* MVS */ #endif /* Header */ if (longwrite((char *)&hdr, (long)sizeof(hdr), outfile) < 0) quit("cannot write icode file"); #if MVS { char *allelse = malloc(hdr.hsize); if (hdr.hsize != fread(allelse, 1, hdr.hsize, toutfile) || longwrite(allelse, hdr.hsize, outfile) < 0) quit("cannot write icode file"); free(allelse); fclose(toutfile); } #endif /* MVS */ } /* * intout(i) outputs i as an int that is used by the runtime system * IntBits/ByteBits bytes must be moved from &word[0] to &codep[0]. */ static novalue intout(oint) int oint; { int i; union { int i; char c[IntBits/ByteBits]; } u; CodeCheck(1); u.i = oint; for (i = 0; i < IntBits/ByteBits; i++) codep[i] = u.c[i]; codep += IntBits/ByteBits; pc += IntBits/ByteBits; } /* * wordout(i) outputs i as a word that is used by the runtime system * WordSize bytes must be moved from &oword[0] to &codep[0]. */ static novalue wordout(oword) word oword; { int i; union { word i; char c[WordSize]; } u; CodeCheck(1); u.i = oword; for (i = 0; i < WordSize; i++) codep[i] = u.c[i]; codep += WordSize; pc += WordSize; } /* * outblock(a,i) output i bytes starting at address a. */ static novalue outblock(addr,count) char *addr; int count; { CodeCheck(count); pc += count; while (count--) *codep++ = *addr++; } #ifdef DeBugLinker /* * dumpblock(a,i) dump contents of i bytes at address a, used only * in conjunction with -L. */ static novalue dumpblock(addr, count) char *addr; int count; { int i; for (i = 0; i < count; i++) { if ((i & 7) == 0) fprintf(dbgfile,"\n\t"); fprintf(dbgfile," %03o",(0377 & (unsigned)addr[i])); } putc('\n',dbgfile); } #endif /* DeBugLinker */ /* * flushcode - write buffered code to the output file. */ static novalue flushcode() { if (codep > codeb) if (longwrite(codeb, DiffPtrs(codep,codeb), outfile) < 0) quit("cannot write icode file"); codep = codeb; } /* * clearlab - clear label table to all zeroes. */ static novalue clearlab() { register int i; for (i = 0; i < maxlabels; i++) labels[i] = 0; } /* * backpatch - fill in all forward references to lab. */ static novalue backpatch(lab) int lab; { word p, r; char *q; char *cp, *cr; register int j; if (lab >= maxlabels) quit("out of label space"); p = labels[lab]; if (p > 0) quit("multiply defined label in ucode"); while (p < 0) { /* follow reference chain */ #ifdef CRAY r = (pc - (WordSize - p))/8; /* compute relative offset */ #else /* CRAY */ r = pc - (WordSize - p); /* compute relative offset */ #endif /* CRAY */ q = codep - (pc + p); /* point to word with address */ cp = (char *) &p; /* address of integer p */ cr = (char *) &r; /* address of integer r */ for (j = 0; j < WordSize; j++) { /* move bytes from word pointed to */ *cp++ = *q; /* by q to p, and move bytes from */ *q++ = *cr++; /* r to word pointed to by q */ } /* moves integers at arbitrary addresses */ } labels[lab] = pc; } #ifdef DeBugLinker novalue idump(s) /* dump code region */ char *s; { int *c; fprintf(stderr,"\ndump of code region %s:\n",s); for (c = (int *)codeb; c < (int *)codep; c++) fprintf(stderr,"%ld: %d\n",(long)c, (int)*c); fflush(stderr); } #endif /* DeBugLinker */