1: #ifndef lint 2: static char *rcsid = 3: "$Header: ffasl.c,v 1.10 83/12/09 16:45:04 sklower Exp $"; 4: #endif 5: 6: /* -[Mon Mar 21 19:37:21 1983 by jkf]- 7: * ffasl.c $Locker: $ 8: * dynamically load C code 9: * 10: * (c) copyright 1982, Regents of the University of California 11: */ 12: 13: 14: #include "global.h" 15: #include <sys/types.h> 16: #include <sys/stat.h> 17: #include <aout.h> 18: #define round(x,s) ((((x)-1) & ~((s)-1)) + (s)) 19: 20: char *stabf = 0, *strcpy(), *sprintf(), *Ilibdir(); 21: extern int fvirgin; 22: static seed=0, mypid = 0; 23: static char myname[100]; 24: lispval verify(); 25: 26: /* dispget - get discipline of function 27: * this is used to handle the tricky defaulting of the discipline 28: * field of such functions as cfasl and getaddress. 29: * dispget is given the value supplied by the caller, 30: * the error message to print if something goes wrong, 31: * the default to use if nil was supplied. 32: * the discipline can be an atom or string. If an atom it is supplied 33: * it must be lambda, nlambda or macro. Otherwise the atoms pname 34: * is used. 35: */ 36: 37: lispval 38: dispget(given,messg,defult) 39: lispval given,defult; 40: char *messg; 41: { 42: int typ; 43: 44: while(TRUE) 45: { 46: if(given == nil) 47: return(defult); 48: if((typ=TYPE(given)) == ATOM) 49: { if(given == lambda || 50: given == nlambda || 51: given == macro) return(given); 52: else return((lispval) given->a.pname); 53: } else if(typ == STRNG) return(given); 54: 55: given = errorh1(Vermisc,messg,nil,TRUE,0,given); 56: } 57: } 58: 59: lispval 60: Lcfasl(){ 61: register struct argent *mlbot = lbot; 62: register lispval work; 63: register int fildes, totsize; 64: int readsize; 65: lispval csegment(); 66: char *sbrk(), *currend, *tfile, cbuf[6000], *mytemp(), *gstab(); 67: char ostabf[128]; 68: struct exec header; 69: char *largs; 70: Savestack(4); 71: 72: switch(np-lbot) { 73: case 3: protect(nil); /* no discipline given */ 74: case 4: protect(nil); /* no library given */ 75: } 76: chkarg(5,"cfasl"); 77: mlbot[0].val = verify(mlbot[0].val,"Incorrect .o file specification"); 78: mlbot[1].val = verify(mlbot[1].val,"Incorrect entry specification for cfasl"); 79: mlbot[3].val = dispget(mlbot[3].val,"Incorrect discipline specification for cfasl",(lispval)Vsubrou->a.pname); 80: while(TYPE(mlbot[2].val)!= ATOM) 81: mlbot[2].val = errorh1(Vermisc,"Bad associated atom name for fasl", 82: nil,TRUE,0,mlbot[2].val); 83: work = mlbot[4].val; 84: if(work==nil) 85: largs = 0; 86: else 87: largs = (char *) verify(work,"Bad loader flags"); 88: 89: /* 90: * Invoke loader. 91: */ 92: strcpy(ostabf,gstab()); 93: currend = sbrk(0); 94: #if (!os_vms) | EUNICE_UNIX_OBJECT_FILE_CFASL 95: /*** UNIX cfasl code ***/ 96: tfile = mytemp(); 97: sprintf(cbuf, 98: "%s/nld -N -x -A %s -T %x %s -e %s -o %s %s -lc", 99: Ilibdir(), 100: ostabf, 101: currend, 102: mlbot[0].val, 103: mlbot[1].val, 104: tfile, 105: largs); 106: /* if nil don't print cfasl/nld message */ 107: if ( Vldprt->a.clb != nil ) { 108: printf(cbuf); 109: putchar('\n'); fflush(stdout); 110: } 111: if(system(cbuf)!=0) { 112: unlink(tfile); 113: ungstab(); 114: fprintf(stderr,"Ld returns error status\n"); 115: Restorestack(); 116: return(nil); 117: } 118: if(fvirgin) 119: fvirgin = 0; 120: else 121: unlink(ostabf); 122: stabf = tfile; 123: if((fildes = open(tfile,0))<0) { 124: fprintf(stderr,"Couldn't open temporary file: %s\n",tfile); 125: Restorestack(); 126: return(nil); 127: } 128: /* 129: * Read a.out header to find out how much room to 130: * allocate and attempt to do so. 131: */ 132: if(read(fildes,(char *)&header,sizeof(header)) <= 0) { 133: close(fildes); 134: Restorestack(); 135: return(nil); 136: } 137: readsize = round(header.a_text,4) + round(header.a_data,4); 138: totsize = readsize + header.a_bss; 139: totsize = round(totsize,512); 140: /* 141: * Fix up system indicators, typing info, etc. 142: */ 143: currend = (char *)csegment(OTHER,totsize,FALSE); 144: 145: if(readsize!=read(fildes,currend,readsize)) 146: {close(fildes);Restorestack(); return(nil);} 147: work = newfunct(); 148: work->bcd.start = (lispval (*)())header.a_entry; 149: work->bcd.discipline = mlbot[3].val; 150: close(fildes); 151: Restorestack(); 152: return(mlbot[2].val->a.fnbnd = work); 153: #else 154: /*** VMS cfasl code ***/ 155: { 156: int pid = getpid() & 0xffff; /* Our process ID number */ 157: char objfil[100]; /* Absolute object file name */ 158: char symfil[100]; /* Old symbol table file */ 159: char filename[100]; /* Random filename buffer */ 160: int strlen(); /* String length function */ 161: int cvt_unix_to_vms(); /* Convert UNIX to VMS filename */ 162: lispval Lgetaddress(),matom(); 163: struct stat stbuf; 164: 165: if (largs == 0) largs = " "; 166: sprintf(objfil,"tmp:cfasl%d.tmp",pid); 167: symfil[cvt_unix_to_vms(ostabf,symfil)] = 0; 168: sprintf(cbuf, /* Create link cmd. */ 169: "$ link/exe=%s/nom/syst=%%X%x/sym=tmp:sym%d.new %s,%s%s", 170: objfil, 171: currend, 172: pid, 173: mlbot[0].val, 174: symfil, 175: largs); 176: printf( /* Echo link cmd. */ 177: "$ link/exe=%s/nomap/system=%%X%x/symbol_table=tmp:sym%d.new %s,%s%s\n", 178: objfil, 179: currend, 180: pid, 181: mlbot[0].val, 182: symfil, 183: largs); 184: fflush(stdout); 185: vms_system(cbuf,0); 186: 187: if ((fildes = open(objfil,0)) < 0) /* Open abs file */ 188: {Restorestack(); return(nil);} 189: fstat(fildes,&stbuf); /* Get its size */ 190: readsize=stbuf.st_size; 191: currend = (char *)csegment(OTHER,readsize,FALSE); 192: readsize = read(fildes,currend,10000000); 193: close(fildes); 194: /* 195: * Delete the absolute object file 196: */ 197: unlink(objfil); 198: /* 199: * Delete the old symbol table (if temporary) 200: */ 201: unlink(sprintf(filename,"tmp:sym%d.stb",pid)); 202: /* 203: * Rename the new symbol table so it is now the old symbol table 204: */ 205: link(sprintf(symfil,"tmp:sym%d.new",pid),filename); 206: unlink(symfil); 207: sprintf(myname,"tmp:sym%d.stb",pid); 208: stabf = myname; 209: /* 210: * Return Lgetaddress(entry,function_name,discipline) 211: */ 212: { 213: struct argent *oldlbot, *oldnp; 214: lispval result; 215: 216: oldlbot = lbot; 217: oldnp = np; 218: lbot = np; 219: np++->val = matom(mlbot[1].val); 220: np++->val = mlbot[2].val; 221: np++->val = matom(mlbot[3].val); 222: result = Lgetaddress(); 223: lbot = oldlbot; 224: np = oldnp; 225: return(result); 226: } 227: } 228: #endif 229: } 230: #ifdef os_vms 231: #define M 4 232: #else 233: #define M 1 234: #endif 235: #define oktox(n) \ 236: (0==stat(n,&stbuf)&&(stbuf.st_mode&S_IFMT)==S_IFREG&&0==access(n,M)) 237: char * 238: gstab() 239: { 240: register char *cp, *cp2; char *getenv(); 241: struct stat stbuf; 242: extern char **Xargv; 243: 244: if(stabf==0) { 245: cp = getenv("PATH"); 246: if(cp==0) 247: cp=":/usr/ucb:/bin:/usr/bin"; 248: if(*cp==':'||*Xargv[0]=='/') { 249: cp++; 250: if(oktox(Xargv[0])) { 251: strcpy(myname,Xargv[0]); 252: return(stabf = myname); 253: } 254: #ifdef os_vms 255: /* 256: * Try Xargv[0] with ".stb" concatenated 257: */ 258: strcpy(myname,Xargv[0]); 259: strcat(myname,".stb"); 260: if (oktox(myname)) return(stabf = myname); 261: /* 262: * Try Xargv[0] with ".exe" concatenated 263: */ 264: strcpy(myname,Xargv[0]); 265: strcat(myname,".exe"); 266: if (oktox(myname)) return(stabf = myname); 267: #endif 268: } 269: for(;*cp;) { 270: 271: /* copy over current directory 272: and then append argv[0] */ 273: 274: for(cp2=myname;(*cp)!=0 && (*cp)!=':';) 275: *cp2++ = *cp++; 276: *cp2++ = '/'; 277: strcpy(cp2,Xargv[0]); 278: if(*cp) cp++; 279: #ifndef os_vms 280: if(!oktox(myname)) continue; 281: #else 282: /* 283: * Also try ".stb" and ".exe" in VMS 284: */ 285: if(!oktox(myname)) { 286: char *end_of_name; 287: end_of_name = cp2 + strlen(cp2); 288: strcat(cp2,".stb"); 289: if(!oktox(myname)) { 290: /* 291: * Try ".exe" 292: */ 293: *end_of_name = 0; /* Kill ".stb" */ 294: strcat(cp2,".exe"); 295: if (!oktox(myname)) continue; 296: } 297: } 298: #endif 299: return(stabf = myname); 300: } 301: /* one last try for dual systems */ 302: strcpy(myname,Xargv[0]); 303: if(oktox(myname)) return(stabf = myname); 304: error("Could not find which file is being executed.",FALSE); 305: /* NOTREACHED */ 306: } else return (stabf); 307: } 308: static char mybuff[40]; 309: char * 310: mytemp() 311: { 312: /*if(mypid==0) mypid = (getpid() & 0xffff); 313: fails if you do a dumplisp after doing a 314: cfasl */ 315: sprintf(mybuff,"/tmp/Li%d.%d",(getpid() & 0xffff),seed++); 316: return(mybuff); 317: } 318: ungstab() 319: { 320: seed--; 321: sprintf(mybuff,"/tmp/Li%d.%d",(getpid() & 0xffff),seed-1); 322: if(seed==0) { 323: stabf = 0; 324: fvirgin = 1; 325: } 326: } 327: lispval 328: verify(in,error) 329: register lispval in; 330: char *error; 331: { 332: for(EVER) { 333: switch(TYPE(in)) { 334: case STRNG: 335: return(in); 336: case ATOM: 337: return((lispval)in->a.pname); 338: } 339: in = errorh1(Vermisc,error,nil,TRUE,0,in); 340: } 341: } 342: 343: 344: /* extern int fvirgin; */ 345: /* declared in ffasl.c tells if this is original 346: * lisp symbol table. 347: * if fvirgin is 1 then we must copy the symbol 348: * table, else we can overwrite it, since 349: * it is a temporary file which only 350: * one user could be using(was not created 351: * as an original lisp or by a (dumplisp) 352: * or a (savelisp)). 353: */ 354: 355: /* copy a block of data from one file to another of size size */ 356: copyblock(f1,f2,size) 357: FILE *f1, *f2; 358: long size; 359: { 360: char block[BUFSIZ]; 361: 362: while ( size > BUFSIZ ) { 363: size -= BUFSIZ; 364: fread(block,BUFSIZ,1,f1); 365: fwrite(block,BUFSIZ,1,f2); 366: } 367: if (size > 0 ) { 368: fread(block,(int)size,1,f1); 369: fwrite(block,(int)size,1,f2); 370: } 371: } 372: 373: /* removeaddress -- 374: * 375: * (removeaddress '|_entry1| '|_entry2| ...) 376: * 377: * removes the given entry points from the run time symbol table, 378: * so that later cfasl'd files can have these label names. 379: * 380: */ 381: 382: lispval 383: Lrmadd(){ 384: register struct argent *mlbot = lbot; 385: register struct nlist *q; 386: register int i; 387: int numberofargs, strsize; 388: char *gstab(); 389: char ostabf[128]; 390: char *nstabf,*mytemp(); 391: char *strtbl,*alloca(); 392: int i2, n, m, nargleft, savem; 393: FILE *f, *fa; 394: FILE *fnew; 395: off_t savesymadd,symadd; /* symbol address */ 396: struct exec buf; 397: struct nlist nlbuf[BUFSIZ/sizeof (struct nlist)]; 398: int maxlen; 399: int change; 400: Keepxs(); 401: 402: numberofargs = (np - lbot); 403: nargleft = numberofargs; 404: maxlen = 0; 405: for ( i=0; i<numberofargs; i++,mlbot ++) { 406: mlbot->val = verify(mlbot->val,"Incorrect entry specification."); 407: n = strlen((char *)mlbot->val); 408: if (n > maxlen) 409: maxlen = n; 410: } 411: /* 412: * Must not disturb object file if it an original file which 413: * other users can execute(signified by the variable fvirgin). 414: * so the entire symbol table is copied to a new file. 415: */ 416: if (fvirgin) { 417: strncpy(ostabf,gstab(),128); 418: nstabf = mytemp(); 419: /* 420: * copy over symbol table into a temporary file first 421: * 422: */ 423: f = fopen(ostabf, "r"); 424: fnew = fopen(nstabf, "w"); 425: if (( f == NULL ) || (fnew == NULL)) {Freexs(); return( nil );} 426: /* read exec header on file */ 427: #ifndef os_vms 428: fread((char *)&buf, sizeof buf, 1, f); 429: #else os_vms 430: /* 431: * Under VMS/EUNICE we have to try the 1st 512 byte 432: * block and the 2nd 512 byte block (there may be 433: * a VMS header in the 1st 512 bytes). 434: */ 435: get_aout_header(fileno(f),&buf); 436: #endif os_vms 437: 438: /* Is this a legitimate a.out file? */ 439: if (N_BADMAG(buf)) { 440: unlink(nstabf); 441: ungstab(); 442: fclose(f); 443: fclose(fnew); 444: errorh1(Vermisc,"Removeaddress: Bad file",nil,FALSE,0,inewstr(ostabf)); 445: {Freexs(); return(nil);} 446: } 447: /* set pointer on read file to symbol table */ 448: /* must be done before the structure buf is reassigned 449: * so that it will be accurate for the read file 450: */ 451: fseek(f,(long)N_SYMOFF(buf),0); 452: /* reset up exec header structure for new file */ 453: buf.a_magic = OMAGIC; 454: buf.a_text = 0; 455: buf.a_data = 0; 456: buf.a_bss = 0; 457: buf.a_entry = 0; 458: buf.a_trsize = 0; 459: buf.a_drsize = 0; 460: fwrite((char *)&buf, 461: sizeof buf,1,fnew); /* write out exec header */ 462: copyblock(f,fnew,(long)buf.a_syms); /* copy symbol table */ 463: #if ! (os_unisoft | os_unix_ts) 464: fread((char *)&strsize, 465: sizeof (int),1,f); /* find size of string table */ 466: fwrite((char *)&strsize, 467: sizeof (int),1,fnew); /* find size of string table */ 468: strsize -= 4; 469: strtbl = alloca(strsize); 470: fread(strtbl,strsize,1,f); /* read and save string table*/ 471: fwrite(strtbl,strsize,1,fnew); /* copy out string table */ 472: #endif 473: fclose(f);fclose(fnew); 474: } else { 475: nstabf = gstab(); 476: } 477: 478: /* 479: * now unset the external bits it the entry points specified. 480: */ 481: f = fopen(nstabf, "r"); 482: fa = fopen(nstabf, "a"); 483: if (( f == NULL ) || (fa == NULL)) { 484: unlink(nstabf); 485: ungstab(); 486: if (f != NULL ) fclose(f); 487: if (fa != NULL ) fclose(fa); 488: return ( nil ); 489: } 490: 491: /* read exec header on file */ 492: #ifndef os_vms 493: fread((char *)&buf, sizeof buf, 1, f); 494: #else os_vms 495: /* 496: * Under VMS/EUNICE we have to try the 1st 512 byte 497: * block and the 2nd 512 byte block (there may be 498: * a VMS header in the 1st 512 bytes). 499: */ 500: get_aout_header(fileno(f),&buf); 501: #endif os_vms 502: 503: /* Is this a legitimate a.out file? */ 504: if (N_BADMAG(buf)) { 505: if (fvirgin) { 506: unlink(nstabf); 507: ungstab(); 508: } 509: fclose(f); 510: fclose(fa); 511: errorh1(Vermisc,"Removeaddress: Bad file",nil,FALSE,0,inewstr(ostabf)); 512: {Freexs(); return(nil);} 513: } else { 514: symadd = N_SYMOFF(buf); 515: #if ! (os_unisoft | os_unix_ts) 516: /* 517: * read in string table if not done during copying 518: */ 519: if (fvirgin==0){ 520: fseek(f,(long)N_STROFF(buf),0); 521: fread((char *)&strsize,sizeof (int),1,f); 522: strsize -= 4; 523: strtbl = alloca(strsize); 524: fread(strtbl,strsize,1,f); 525: } 526: #endif 527: n = buf.a_syms; 528: fseek(f, (long)symadd, 0); 529: while (n) { 530: m = sizeof (nlbuf); 531: if (n < m) 532: m = n; 533: 534: /* read next block of symbols from a.out file */ 535: fread((char *)nlbuf, m, 1, f); 536: savem = m; 537: savesymadd = symadd; 538: symadd += m; 539: n -= m; 540: change = 0; 541: 542: /* compare block of symbols against list of entry point 543: * names given, if a match occurs, clear the N_EXT bit 544: * for that given symbol and signal a change. 545: */ 546: for (q = nlbuf; (m -= sizeof(struct nlist)) >= 0; q++) { 547: 548: /* make sure it is external */ 549: if ( 550: (q->n_type & N_EXT)==0 551: #if ! (os_unix_ts | os_unisoft) 552: || q->n_un.n_strx == 0 || q->n_type & N_STAB 553: #endif 554: ) continue; 555: for (mlbot=lbot,i2 = 0;i2<numberofargs;i2++,mlbot++) { 556: #if ! (os_unix_ts | os_unisoft) 557: if(strcmp((char *)mlbot->val, 558: strtbl+q->n_un.n_strx-4)!=0) 559: continue; 560: #else 561: if(strncmp((char *)mlbot->val, 562: q->n_name,8)!=0) 563: continue; 564: #endif 565: change = 1; 566: q->n_type &= ~N_EXT; 567: break; 568: } 569: } 570: if ( change ) { 571: fseek(fa,(long)savesymadd,0); 572: fwrite((char *)nlbuf, savem, 1, fa); 573: if (--nargleft == 0) 574: goto alldone; 575: } 576: } 577: } 578: alldone: 579: fclose(f); 580: fclose(fa); 581: if(fvirgin) 582: fvirgin = 0; 583: stabf = nstabf; 584: {Freexs(); return(tatom);} 585: } 586: char * 587: Ilibdir() 588: { 589: register lispval handy; 590: tryagain: 591: handy = Vlibdir->a.clb; 592: switch(TYPE(handy)) { 593: case ATOM: 594: handy = (lispval) handy->a.pname; 595: case STRNG: 596: break; 597: default: 598: (void) error( 599: "cfasl or load: lisp-library-directory not bound to string or atom", 600: TRUE); 601: goto tryagain; 602: } 603: return((char *) handy); 604: }