|
|
1.1 root 1: static char *sccsid = "@(#)nfasl.c 34.5 10/13/80";
2:
3: #include "global.h"
4: #include <sys/types.h>
5: #include <pagsiz.h>
6: #include "naout.h"
7: #include "chkrtab.h"
8: #include "structs.h"
9:
10: /* fasl - fast loader j.k.foderaro
11: * this loader is tuned for the lisp fast loading application
12: * any changes in the system loading procedure will require changes
13: * to this file
14: *
15: * The format of the object file we read as input:
16: * text segment:
17: * 1) program text - this comes first.
18: * 2) binder table - one word entries, see struct bindage
19: * begins with symbol: bind_org
20: * 3) litterals - exploded lisp objects.
21: * begins with symbol: lit_org
22: * ends with symbol: lit_end
23: * data segment:
24: * not used
25: *
26: *
27: * these segments are created permanently in memory:
28: * code segment - contains machine codes to evaluate lisp functions.
29: * linker segment - a list of pointers to lispvals. This allows the
30: * compiled code to reference constant lisp objects.
31: * The first word of the linker segment is a gc link
32: * pointer and does not point to a literal. The
33: * symbol binder is assumed to point to the second
34: * longword in this segment. The last word in the
35: * table is -1 as a sentinal to the gc marker.
36: * The number of real entries in the linker segment
37: * is given as the value of the linker_size symbol.
38: * Taking into account the 2 words required for the
39: * gc, there are 4*linker_size + 8 bytes in this segment.
40: * transfer segment - this is a transfer table block. It is used to
41: * allow compiled code to call other functions
42: * quickly. The number of entries in the transfer table is
43: * given as the value of the trans_size symbol.
44: *
45: * the following segments are set up in memory temporarily then flushed
46: * binder segment - a list of struct bindage entries. They describe
47: * what to do with the literals read from the literal
48: * table. The binder segment begins in the file
49: * following the bindorg symbol.
50: * literal segment - a list of characters which _Lread will read to
51: * create the lisp objects. The order of the literals
52: * is:
53: * linker literals - used to fill the linker segment.
54: * transfer table literals - used to fill the
55: * transfer segment
56: * binder literals - these include names of functions
57: * to bind interspersed with forms to evaluate.
58: * The meanings of the binder literals is given by
59: * the values in the binder segment.
60: * string segment - this is the string table from the file. We have
61: * to allocate space for it in core to speed up
62: * symbol referencing.
63: *
64: */
65:
66:
67: /* external functions called or referenced */
68:
69: lispval qcons(),qlinker(),qget();
70: int _qf0(), _qf1(), _qf2(), _qf3(), _qf4(), _qfuncl(), svkludg(),qnewint();
71: lispval Lread(), Lcons(), Lminus(), Ladd1(), Lsub1(), Lplist(), Lputprop();
72: lispval Lprint(), Lpatom(), Lconcat(), Lget(), Lmapc(), Lmapcan();
73: lispval Llist(), Ladd(), Lgreaterp(), Lequal(), Ltimes(), Lsub();
74: lispval Lncons();
75: lispval Idothrow(),error();
76: lispval Istsrch();
77: int mcount();
78: extern int mcounts[],mcountp,doprof;
79:
80: extern lispval *tynames[];
81: extern long errp;
82: extern char _erthrow[];
83: extern char setsav[];
84:
85: extern int initflag; /* when TRUE, inhibits gc */
86:
87: char *alloca(); /* stack space allocator */
88:
89: /* mini symbol table, contains the only external symbols compiled code
90: is allowed to reference
91: */
92:
93: #define SYMMAX 16
94: struct ssym { char *fnam; /* pointer to string containing name */
95: int floc; /* address of symbol */
96: int ord; /* ordinal number within cur sym tab */
97:
98: } Symbtb[SYMMAX]
99: = {
100: "trantb", 0, -1, /* must be first */
101: "linker", 0, -1, /* must be second */
102: "mcount", (int) mcount, -1,
103: "mcounts", (int) mcounts, -1,
104: "_qnewint", (int) qnewint, -1,
105: "_qcons", (int) qcons, -1,
106: "_typetable", (int) typetable, -1,
107: "_tynames", (int) tynames, -1,
108: "_qget", (int) qget, -1,
109: "_errp", (int) &errp, -1,
110: "_Idothrow", (int) Idothrow, -1,
111: "__erthrow", (int) _erthrow, -1,
112: "_error", (int) error, -1,
113: "_setsav", (int) setsav, -1,
114: "_svkludg", (int) svkludg, -1,
115: "_bnp", (int) &bnp, -1,
116: };
117:
118: struct nlist syml; /* to read a.out symb tab */
119: extern lispval *bind_lists; /* gc binding lists */
120:
121: /* bindage structure:
122: * the bindage structure describes the linkages of functions and name,
123: * and tells which functions should be evaluated. It is mainly used
124: * for the non-fasl'ing of files, we only use one of the fields in fasl
125: */
126: struct bindage
127: {
128: int b_type; /* type code, as described below */
129: };
130:
131: /* the possible values of b_type
132: * -1 - this is the end of the bindage entries
133: * 0 - this is a lambda function
134: * 1 - this is a nlambda function
135: * 2 - this is a macro function
136: * 99 - evaluate the string
137: *
138: */
139:
140:
141: extern struct trtab *trhead; /* head of list of transfer tables */
142: extern struct trent *trcur; /* next entry to allocate */
143: extern int trleft; /* # of entries left in this transfer table */
144:
145: struct trent *gettran(); /* function to allocate entries */
146:
147: /* maximum number of functions */
148: #define MAXFNS 500
149:
150: lispval Lnfasl()
151: {
152: extern int holend,usehole;
153: extern int uctolc;
154: extern char *curhbeg;
155: struct argent *svnp;
156: struct exec exblk; /* stores a.out header */
157: FILE *filp, *p, *map; /* file pointer */
158: int domap,note_redef;
159: lispval handy,debugmode;
160: struct relocation_info reloc;
161: struct trent *tranloc;
162: int trsize;
163: lispval disp;
164: int i,j,times, *iptr, oldinitflag;
165: int funloc[MAXFNS]; /* addresses of functions rel to txt org */
166: int funcnt = 0;
167:
168: /* symbols whose values are taken from symbol table of .o file */
169: int bind_org = 0; /* beginning of bind table */
170: int lit_org = 0; /* beginning of literal table */
171: int lit_end; /* end of literal table */
172: int trans_size = 0; /* size in entries of transfer table */
173: int linker_size; /* size in bytes of linker table
174: (not counting gc ptr) */
175:
176: /* symbols which hold the locations of the segments in core and
177: * in the file
178: */
179: char *code_core_org, /* beginning of code segment */
180: *linker_core_org, /* beginning of linker segment */
181: *linker_core_end, /* last word in linker segment */
182: *literal_core_org, /* beginning of literal table */
183: *binder_core_org, /* beginning of binder table */
184: *string_core_org;
185:
186: int string_file_org, /* location of string table in file */
187: string_size, /* number of chars in string table */
188: segsiz; /* size of permanent incore segment */
189:
190: char *symbol_name;
191: struct bindage *bindorg, *curbind;
192: int linkerloc, typer;
193: lispval rdform, *linktab;
194: int ouctolc;
195: int debug = 0;
196: lispval currtab,curibase;
197: char ch,*filnm;
198: char tempfilbf[100];
199:
200:
201: switch(np-lbot) {
202: case 0:
203: protect(nil);
204: case 1:
205: protect(nil);
206: case 2:
207: protect(nil);
208: case 3:
209: break;
210: default:
211: argerr("fasl");
212: }
213: filnm = (char *) verify(lbot->val,"fasl: non atom arg");
214:
215:
216: domap = FALSE;
217: /* debugging */
218: debugmode = Istsrch(matom("debugging"))->d.cdr->d.cdr->d.cdr;
219: /* end debugging */
220:
221:
222: /* insure that the given file name ends in .o
223: if it doesnt, copy to a new buffer and add a .o
224: */
225: tempfilbf[0] = '\0';
226: if( (i = strlen(filnm)) < 2 ||
227: strcmp(filnm+i-2,".o") != 0)
228: {
229: strcatn(tempfilbf,filnm,96);
230: strcat(tempfilbf,".o");
231: filnm = tempfilbf;
232: }
233:
234: if ( (filp = fopen(filnm,"r")) == NULL)
235: errorh(Vermisc,"Can't open file",nil,FALSE,9797,lbot->val);
236:
237: if ((handy = (lbot+1)->val) != nil )
238: {
239: if((TYPE(handy) != ATOM ) ||
240: (map = fopen(handy->a.pname,
241: (Istsrch(matom("appendmap"))->d.cdr->d.cdr->d.cdr == nil
242: ? "w" : "a"))) == NULL)
243: error("fasl: can't open map file",FALSE);
244: else
245: { domap = TRUE;
246: /* fprintf(map,"Map of file %s\n",lbot->val->a.pname); */
247: }
248: }
249:
250: /* set the note redefinition flag */
251: if((lbot+2)->val != nil) note_redef = TRUE;
252: else note_redef = FALSE;
253:
254: printf("[fasl %s]",filnm);
255: fflush(stdout);
256: svnp = np;
257:
258: lbot = np; /* set up base for later calls */
259:
260:
261: /* clear the ords in the symbol table */
262: for(i=0 ; i < SYMMAX ; i++) Symbtb[i].ord = -1;
263:
264: if( read(fileno(filp),&exblk,sizeof(struct exec))
265: != sizeof(struct exec))
266: error("fasl: header read failed",FALSE);
267:
268: /* check that the magic number is valid */
269:
270: if(exblk.a_magic != 0407) error("fasl: bad magic number in fasl file",FALSE);
271:
272: /* read in string table */
273: lseek(fileno(filp),(string_file_org = N_STROFF(exblk)),0);
274: if( read(fileno(filp), &string_size , 4) != 4)
275: error("fasl: string table read error, probably old fasl format", FALSE);
276:
277: /* allocate space for string table on the stack */
278: string_core_org = alloca(string_size - 4);
279:
280: if( read(fileno(filp), string_core_org , string_size - 4)
281: != string_size -4) error("fasl: string table read error ",FALSE);
282: /* read in symbol table and set the ordinal values */
283:
284: fseek(filp,N_SYMOFF(exblk),0);
285:
286: times = exblk.a_syms/sizeof(struct nlist);
287: if(debug) printf(" %d symbols in symbol table\n",times);
288:
289: for(i=0; i < times ; i++)
290: {
291: if( fread(&syml,sizeof(struct nlist),1,filp) != 1)
292: error("fasl: Symb tab read error",FALSE);
293:
294: symbol_name = syml.n_un.n_strx - 4 + string_core_org;
295: if (syml.n_type == N_EXT)
296: {
297: for(j=0; j< SYMMAX; j++)
298: {
299: if((Symbtb[j].ord < 0)
300: && strcmp(Symbtb[j].fnam,symbol_name)==0)
301: { Symbtb[j].ord = i;
302: if(debug)printf("symbol %s ord is %d\n",symbol_name,i);
303: break;
304: };
305:
306: };
307:
308: if( j>=SYMMAX ) printf("Unknown symbol %s\n",symbol_name);
309: }
310: else if (((ch = symbol_name[0]) == 's')
311: || (ch == 'L')
312: || (ch == '.') ) ; /* skip this */
313: else if (symbol_name[0] == 'F')
314: funloc[funcnt++] = syml.n_value; /* seeing function */
315: else if (!bind_org && (strcmp(symbol_name, "bind_org") == 0))
316: bind_org = syml.n_value;
317: else if (strcmp(symbol_name, "lit_org") == 0)
318: lit_org = syml.n_value;
319: else if (strcmp(symbol_name, "lit_end") == 0)
320: lit_end = syml.n_value;
321: else if (strcmp(symbol_name, "trans_size") == 0)
322: trans_size = syml.n_value;
323: else if (strcmp(symbol_name, "linker_size") == 0)
324: linker_size = syml.n_value;
325: }
326:
327: /* check to make sure we are working with the right format */
328: if((lit_org == 0) || (lit_end == 0))
329: errorh(Vermisc,"File not in new fasl format",nil,FALSE,0,lbot->val);
330:
331: /*----------------*/
332:
333: /* read in text segment up to beginning of binder table */
334:
335: segsiz = bind_org + 4*linker_size + 8 + 3; /* size is core segment size
336: * plus linker table size
337: * plus 2 for gc list
338: * plus 3 to round up to word
339: */
340:
341: lseek(fileno(filp),(long)sizeof(struct exec),0);
342: code_core_org = (char *) csegment(str_name,segsiz/4,TRUE);
343: if(read(fileno(filp),code_core_org,bind_org) != bind_org)
344: error("Read error in text ",FALSE);
345:
346: if(debug) {
347: printf("Read %d bytes of text into 0x%x\n",bind_org,code_core_org);
348: printf(" incore segment size: %d (0x%x)\n",segsiz,segsiz);
349: }
350:
351: /* linker table is 2 entries (8 bytes) larger than the number of
352: * entries given by linker_size . There must be a gc word at
353: * the beginning and a -1 at the end
354: */
355: linker_core_org = code_core_org + bind_org;
356: linker_core_end = linker_core_org + 4*linker_size + 4;
357: /* address of gc sentinal last */
358:
359: if(debug)printf("lin_cor_org: %x, link_cor_end %x\n",
360: linker_core_org,
361: linker_core_end);
362: Symbtb[1].floc = (int) (linker_core_org + 4);
363:
364: /* set the linker table to all -1's so we can put in the gc table */
365: for( iptr = (int *)(linker_core_org + 4 );
366: iptr <= (int *)(linker_core_end);
367: iptr++)
368: *iptr = -1;
369:
370:
371: /* link our table into the gc tables */
372: *(int *)linker_core_org = (int)bind_lists; /* point to current */
373: bind_lists = (lispval *) (linker_core_org + 4); /* point to first item */
374:
375: /* read the binder table and literals onto the stack */
376:
377: binder_core_org = alloca(lit_end - bind_org);
378: read(fileno(filp),binder_core_org,lit_end-bind_org);
379:
380: literal_core_org = binder_core_org + lit_org - bind_org;
381:
382: /* check if there is a transfer table required for this
383: * file, and if so allocate one of the necessary size
384: */
385:
386: if(trans_size > 0)
387: {
388: tranloc = gettran(trans_size);
389: Symbtb[0].floc = (int) tranloc;
390: }
391:
392: /* now relocate the necessary symbols in the text segment */
393:
394: fseek(filp,(long)(sizeof(struct exec) + exblk.a_text + exblk.a_data),0);
395: times = (exblk.a_trsize)/sizeof(struct relocation_info);
396:
397: /* the only symbols we will relocate are references to
398: external symbols. They are recognized by
399: extern and pcrel set.
400: */
401:
402: for( i=1; i<=times ; i++)
403: {
404: if( fread(&reloc,sizeof(struct relocation_info),1,filp) != 1)
405: error("Bad text reloc read",FALSE);
406: if(reloc.r_extern && reloc.r_pcrel)
407: {
408: for(j=0; j < SYMMAX; j++)
409: {
410:
411: if(Symbtb[j].ord == reloc.r_symbolnum) /* look for this sym */
412: {
413: if(debug && FALSE) printf("Relocating %d (ord %d) at %x\n",
414: j, Symbtb[j].ord, reloc.r_address);
415: if (Symbtb[j].floc == (int) mcounts) {
416: *(int *)(code_core_org+reloc.r_address)
417: += mcountp - (int)code_core_org;
418: if(doprof){
419: if (mcountp == (int) &mcounts[NMCOUNT-2])
420: printf("Ran out of counters; increas NMCOUNT in fasl.c\n");
421: if (mcountp < (int) &mcounts[NMCOUNT-1])
422: mcountp += 4;
423: }
424: } else
425: *(int *)(code_core_org+reloc.r_address)
426: += Symbtb[j].floc - (int)code_core_org;
427:
428: break;
429:
430: }
431: };
432: if( j >= SYMMAX) if(debug) printf("Couldnt find ord # %d\n",
433: reloc.r_symbolnum);
434: }
435:
436: }
437:
438: putchar('\n');
439: fflush(stdout);
440:
441: /* set up a fake port so we can read from core */
442: /* first find a free port */
443:
444: p = stdin;
445: for( ; p->_flag & (_IOREAD|_IOWRT) ; p++)
446: if( p >= _iob + _NFILE)
447: error(" No free file descriptor for fasl ",FALSE);
448:
449: p->_flag = _IOREAD | _IOSTRG;
450: p->_base = p->_ptr = (char *) literal_core_org; /* start at beginning of lit */
451: p->_cnt = lit_end - lit_org;
452:
453: if(debug)printf("lit_org %d, charstrt %d\n",lit_org, p->_base);
454: /* the first forms we wish to read are those literals in the
455: * literal table, that is those forms referenced by an offset
456: * from r8 in compiled code
457: */
458:
459: /* to read in the forms correctly, we must set up the read table
460: */
461: currtab = Vreadtable->a.clb;
462: Vreadtable->a.clb = strtab; /* standard read table */
463: curibase = ibase->a.clb;
464: ibase->a.clb = inewint(10); /* read in decimal */
465: ouctolc = uctolc; /* remember value of uctolc flag */
466:
467: oldinitflag = initflag; /* remember current val */
468: initflag = TRUE; /* turn OFF gc */
469: i = 1;
470: linktab = (lispval *)(linker_core_org +4);
471: while (linktab < (lispval *)linker_core_end)
472: {
473: np = svnp;
474: protect(P(p));
475: uctolc = FALSE;
476: handy = Lread();
477: uctolc = ouctolc;
478: getc(p); /* eat trailing blank */
479: if(debugmode)
480: { printf("form %d read: ",i++);
481: printr(handy,stdout);
482: putchar('\n');
483: fflush(stdout);
484: }
485: *linktab++ = handy;
486: }
487:
488: /* process the transfer table if one is used */
489: trsize = trans_size;
490: while(trsize--)
491: {
492: np = svnp;
493: protect(P(p));
494: uctolc = FALSE;
495: handy = Lread(); /* get function name */
496: uctolc = ouctolc;
497: getc(p);
498: tranloc->name = handy;
499: tranloc->fcn = qlinker; /* initially go to qlinker */
500: tranloc++;
501: }
502:
503:
504:
505: /* now process the binder table, which contains pointers to
506: functions to link in and forms to evaluate.
507: */
508: funcnt = 0;
509:
510: curbind = (struct bindage *) binder_core_org;
511: for( ; curbind->b_type != -1 ; curbind++)
512: {
513: np = svnp;
514: protect(P(p));
515: uctolc = FALSE; /* inhibit uctolc conversion */
516: rdform = Lread();
517: /* debugging */
518: if(debugmode) { printf("link form read: ");
519: printr(rdform,stdout);
520: printf(" ,type: %d\n",
521: curbind->b_type);
522: fflush(stdout);
523: }
524: /* end debugging */
525: uctolc = ouctolc; /* restore previous state */
526: getc(p); /* eat trailing null */
527: protect(rdform);
528: if(curbind->b_type <= 2) /* if function type */
529: {
530: handy = newfunct();
531: if (note_redef && (rdform->a.fnbnd != nil))
532: {
533: printr(rdform,stdout);
534: printf(" redefined\n");
535: }
536: rdform->a.fnbnd = handy;
537: handy->bcd.entry = (lispval (*)())(code_core_org + funloc[funcnt++]);
538: handy->bcd.discipline =
539: (curbind->b_type == 0 ? lambda :
540: curbind->b_type == 1 ? nlambda :
541: macro);
542: if(domap) fprintf(map,"%s\n%x\n",rdform->a.pname,handy->bcd.entry);
543: }
544: else {
545: Vreadtable->a.clb = currtab;
546: ibase->a.clb = curibase;
547:
548: /* debugging */
549: if(debugmode) {
550: printf("Eval: ");
551: printr(rdform,stdout);
552: printf("\n");
553: fflush(stdout);
554: };
555: /* end debugging */
556:
557: eval(rdform); /* otherwise eval it */
558:
559: if(uctolc) ouctolc = TRUE; /* if changed by eval, remember */
560: curibase = ibase->a.clb;
561: ibase->a.clb = inewint(10);
562: Vreadtable->a.clb = strtab;
563: }
564: };
565:
566: p->_cnt = p->_file = p->_flag = 0; /* give up file descriptor */
567: p->_ptr = p-> _base = (char *) 0;
568: initflag = oldinitflag; /* restore state of gc */
569: Vreadtable->a.clb = currtab;
570: chkrtab(currtab);
571: ibase->a.clb = curibase;
572:
573: fclose(filp);
574: if(domap) fclose(map);
575: return(tatom);
576: }
577:
578:
579: /* gettran :: allocate a segment of transfer table of the given size */
580:
581: struct trent *
582: gettran(size)
583: {
584: struct trtab *trp;
585: struct trent *retv;
586: int ousehole;
587: extern int usehole;
588:
589: if(size > TRENTS)
590: error("transfer table too large",FALSE);
591:
592: if(size > trleft)
593: {
594: /* allocate a new transfer table */
595: /* must not allocate in the hole or we cant modify it */
596: ousehole = usehole; /* remember old value */
597: usehole = FALSE;
598: trp = (struct trtab *)csegment(str_name,sizeof(struct trtab),FALSE);
599: usehole = ousehole;
600:
601: trp->sentinal = 0; /* make sure the sentinal is 0 */
602: trp->nxtt = trhead; /* link at beginning of table */
603: trhead = trp;
604: trcur = &(trp->trentrs[0]); /* begin allocating here */
605: trleft = TRENTS;
606: }
607:
608: trleft = trleft - size;
609: retv = trcur;
610: trcur = trcur + size;
611: return(retv);
612: }
613:
614: /* clrtt :: clear transfer tables, or link them all up;
615: * this has two totally opposite functions:
616: * 1) all transfer tables are reset so that all function calls will go
617: * through qlinker
618: * 2) as many transfer tables are set up to point to bcd functions
619: * as possible
620: */
621: clrtt(flag)
622: {
623: /* flag = 0 :: set to qlinker
624: * flag = 1 :: set to function bcd binding if possible
625: */
626: register struct trtab *temptt;
627: register struct trent *tement;
628: register lispval fnb;
629:
630: for (temptt = trhead; temptt != 0 ; temptt = temptt->nxtt)
631: {
632: for(tement = &temptt->trentrs[0] ; tement->fcn != 0 ; tement++)
633: { if(flag == 0 || TYPE(fnb=tement->name->a.fnbnd) != BCD
634: || TYPE(fnb->bcd.discipline) == STRNG)
635: tement->fcn = qlinker;
636: else tement->fcn = fnb->bcd.entry;
637: }
638: }
639: }
640:
641: /* chktt - builds a list of transfer table entries which don't yet have
642: a function associated with them, i.e if this transfer table entry
643: were used, an undefined function error would result
644: */
645: lispval
646: chktt()
647: {
648: register struct trtab *temptt;
649: register struct trent *tement;
650: register lispval retlst,curv;
651:
652: snpand(4);
653:
654: retlst = newdot(); /* build list of undef functions */
655: protect(retlst);
656: for (temptt = trhead; temptt != 0 ; temptt = temptt->nxtt)
657: {
658: for(tement = &temptt->trentrs[0] ; tement->fcn != 0 ; tement++)
659: {
660: if(tement->name->a.fnbnd == nil)
661: {
662: curv= newdot();
663: curv->d.car = tement->name;
664: curv->d.cdr = retlst->d.cdr;
665: retlst->d.cdr = curv;
666: }
667: }
668: }
669: return(retlst->d.cdr);
670: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.