|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)ld.c 4.9 7/1/83"; ! 3: #endif ! 4: ! 5: /* ! 6: * ld - string table version for VAX ! 7: */ ! 8: ! 9: #include <sys/types.h> ! 10: #include <signal.h> ! 11: #include <stdio.h> ! 12: #include <ctype.h> ! 13: #include <ar.h> ! 14: #include <a.out.h> ! 15: #include <ranlib.h> ! 16: #include <sys/stat.h> ! 17: ! 18: /* ! 19: * Basic strategy: ! 20: * ! 21: * The loader takes a number of files and libraries as arguments. ! 22: * A first pass examines each file in turn. Normal files are ! 23: * unconditionally loaded, and the (external) symbols they define and require ! 24: * are noted in the symbol table. Libraries are searched, and the ! 25: * library members which define needed symbols are remembered ! 26: * in a special data structure so they can be selected on the second ! 27: * pass. Symbols defined and required by library members are also ! 28: * recorded. ! 29: * ! 30: * After the first pass, the loader knows the size of the basic text ! 31: * data, and bss segments from the sum of the sizes of the modules which ! 32: * were required. It has computed, for each ``common'' symbol, the ! 33: * maximum size of any reference to it, and these symbols are then assigned ! 34: * storage locations after their sizes are appropriately rounded. ! 35: * The loader now knows all sizes for the eventual output file, and ! 36: * can determine the final locations of external symbols before it ! 37: * begins a second pass. ! 38: * ! 39: * On the second pass each normal file and required library member ! 40: * is processed again. The symbol table for each such file is ! 41: * reread and relevant parts of it are placed in the output. The offsets ! 42: * in the local symbol table for externally defined symbols are recorded ! 43: * since relocation information refers to symbols in this way. ! 44: * Armed with all necessary information, the text and data segments ! 45: * are relocated and the result is placed in the output file, which ! 46: * is pasted together, ``in place'', by writing to it in several ! 47: * different places concurrently. ! 48: */ ! 49: ! 50: /* ! 51: * Internal data structures ! 52: * ! 53: * All internal data structures are segmented and dynamically extended. ! 54: * The basic structures hold 1103 (NSYM) symbols, ~~200 (NROUT) ! 55: * referenced library members, and 100 (NSYMPR) private (local) symbols ! 56: * per object module. For large programs and/or modules, these structures ! 57: * expand to be up to 40 (NSEG) times as large as this as necessary. ! 58: */ ! 59: #define NSEG 40 /* Number of segments, each data structure */ ! 60: #define NSYM 1103 /* Number of symbols per segment */ ! 61: #define NROUT 250 /* Number of library references per segment */ ! 62: #define NSYMPR 100 /* Number of private symbols per segment */ ! 63: ! 64: /* ! 65: * Structure describing each symbol table segment. ! 66: * Each segment has its own hash table. We record the first ! 67: * address in and first address beyond both the symbol and hash ! 68: * tables, for use in the routine symx and the lookup routine respectively. ! 69: * The symfree routine also understands this structure well as it used ! 70: * to back out symbols from modules we decide that we don't need in pass 1. ! 71: * ! 72: * Csymseg points to the current symbol table segment; ! 73: * csymseg->sy_first[csymseg->sy_used] is the next symbol slot to be allocated, ! 74: * (unless csymseg->sy_used == NSYM in which case we will allocate another ! 75: * symbol table segment first.) ! 76: */ ! 77: struct symseg { ! 78: struct nlist *sy_first; /* base of this alloc'ed segment */ ! 79: struct nlist *sy_last; /* end of this segment, for n_strx */ ! 80: int sy_used; /* symbols used in this seg */ ! 81: struct nlist **sy_hfirst; /* base of hash table, this seg */ ! 82: struct nlist **sy_hlast; /* end of hash table, this seg */ ! 83: } symseg[NSEG], *csymseg; ! 84: ! 85: /* ! 86: * The lookup routine uses quadratic rehash. Since a quadratic rehash ! 87: * only probes 1/2 of the buckets in the table, and since the hash ! 88: * table is segmented the same way the symbol table is, we make the ! 89: * hash table have twice as many buckets as there are symbol table slots ! 90: * in the segment. This guarantees that the quadratic rehash will never ! 91: * fail to find an empty bucket if the segment is not full and the ! 92: * symbol is not there. ! 93: */ ! 94: #define HSIZE (NSYM*2) ! 95: ! 96: /* ! 97: * Xsym converts symbol table indices (ala x) into symbol table pointers. ! 98: * Symx (harder, but never used in loops) inverts pointers into the symbol ! 99: * table into indices using the symseg[] structure. ! 100: */ ! 101: #define xsym(x) (symseg[(x)/NSYM].sy_first+((x)%NSYM)) ! 102: /* symx() is a function, defined below */ ! 103: ! 104: struct nlist cursym; /* current symbol */ ! 105: struct nlist *lastsym; /* last symbol entered */ ! 106: struct nlist *nextsym; /* next available symbol table entry */ ! 107: struct nlist *addsym; /* first sym defined during incr load */ ! 108: int nsym; /* pass2: number of local symbols in a.out */ ! 109: /* nsym + symx(nextsym) is the symbol table size during pass2 */ ! 110: ! 111: struct nlist **lookup(), **slookup(); ! 112: struct nlist *p_etext, *p_edata, *p_end, *entrypt; ! 113: ! 114: /* ! 115: * Definitions of segmentation for library member table. ! 116: * For each library we encounter on pass 1 we record pointers to all ! 117: * members which we will load on pass 2. These are recorded as offsets ! 118: * into the archive in the library member table. Libraries are ! 119: * separated in the table by the special offset value -1. ! 120: */ ! 121: off_t li_init[NROUT]; ! 122: struct libseg { ! 123: off_t *li_first; ! 124: int li_used; ! 125: int li_used2; ! 126: } libseg[NSEG] = { ! 127: li_init, 0, 0, ! 128: }, *clibseg = libseg; ! 129: ! 130: /* ! 131: * In processing each module on pass 2 we must relocate references ! 132: * relative to external symbols. These references are recorded ! 133: * in the relocation information as relative to local symbol numbers ! 134: * assigned to the external symbols when the module was created. ! 135: * Thus before relocating the module in pass 2 we create a table ! 136: * which maps these internal numbers to symbol table entries. ! 137: * A hash table is constructed, based on the local symbol table indices, ! 138: * for quick lookup of these symbols. ! 139: */ ! 140: #define LHSIZ 31 ! 141: struct local { ! 142: int l_index; /* index to symbol in file */ ! 143: struct nlist *l_symbol; /* ptr to symbol table */ ! 144: struct local *l_link; /* hash link */ ! 145: } *lochash[LHSIZ], lhinit[NSYMPR]; ! 146: struct locseg { ! 147: struct local *lo_first; ! 148: int lo_used; ! 149: } locseg[NSEG] = { ! 150: lhinit, 0 ! 151: }, *clocseg; ! 152: ! 153: /* ! 154: * Libraries are typically built with a table of contents, ! 155: * which is the first member of a library with special file ! 156: * name __.SYMDEF and contains a list of symbol names ! 157: * and with each symbol the offset of the library member which defines ! 158: * it. The loader uses this table to quickly tell which library members ! 159: * are (potentially) useful. The alternative, examining the symbol ! 160: * table of each library member, is painfully slow for large archives. ! 161: * ! 162: * See <ranlib.h> for the definition of the ranlib structure and an ! 163: * explanation of the __.SYMDEF file format. ! 164: */ ! 165: int tnum; /* number of symbols in table of contents */ ! 166: int ssiz; /* size of string table for table of contents */ ! 167: struct ranlib *tab; /* the table of contents (dynamically allocated) */ ! 168: char *tabstr; /* string table for table of contents */ ! 169: ! 170: /* ! 171: * We open each input file or library only once, but in pass2 we ! 172: * (historically) read from such a file at 2 different places at the ! 173: * same time. These structures are remnants from those days, ! 174: * and now serve only to catch ``Premature EOF''. ! 175: * In order to make I/O more efficient, we provide routines which ! 176: * work in hardware page sizes. The associated constants are defined ! 177: * as BLKSIZE, BLKSHIFT, and BLKMASK. ! 178: */ ! 179: #define BLKSIZE 1024 ! 180: #define BLKSHIFT 10 ! 181: #define BLKMASK (BLKSIZE - 1) ! 182: typedef struct { ! 183: short *fakeptr; ! 184: int bno; ! 185: int nibuf; ! 186: int nuser; ! 187: char buff[BLKSIZE]; ! 188: } PAGE; ! 189: ! 190: PAGE page[2]; ! 191: ! 192: struct { ! 193: short *fakeptr; ! 194: int bno; ! 195: int nibuf; ! 196: int nuser; ! 197: } fpage; ! 198: ! 199: typedef struct { ! 200: char *ptr; ! 201: int bno; ! 202: int nibuf; ! 203: long size; ! 204: long pos; ! 205: PAGE *pno; ! 206: } STREAM; ! 207: ! 208: STREAM text; ! 209: STREAM reloc; ! 210: ! 211: /* ! 212: * Header from the a.out and the archive it is from (if any). ! 213: */ ! 214: struct exec filhdr; ! 215: struct ar_hdr archdr; ! 216: #define OARMAG 0177545 ! 217: ! 218: /* ! 219: * Options. ! 220: */ ! 221: int trace; ! 222: int xflag; /* discard local symbols */ ! 223: int Xflag; /* discard locals starting with 'L' */ ! 224: int Sflag; /* discard all except locals and globals*/ ! 225: int rflag; /* preserve relocation bits, don't define common */ ! 226: int arflag; /* original copy of rflag */ ! 227: int sflag; /* discard all symbols */ ! 228: int Mflag; /* print rudimentary load map */ ! 229: int nflag; /* pure procedure */ ! 230: int dflag; /* define common even with rflag */ ! 231: int zflag; /* demand paged */ ! 232: long hsize; /* size of hole at beginning of data to be squashed */ ! 233: int Aflag; /* doing incremental load */ ! 234: int Nflag; /* want impure a.out */ ! 235: int funding; /* reading fundamental file for incremental load */ ! 236: int yflag; /* number of symbols to be traced */ ! 237: char **ytab; /* the symbols */ ! 238: ! 239: /* ! 240: * These are the cumulative sizes, set in pass 1, which ! 241: * appear in the a.out header when the loader is finished. ! 242: */ ! 243: off_t tsize, dsize, bsize, trsize, drsize, ssize; ! 244: ! 245: /* ! 246: * Symbol relocation: c?rel is a scale factor which is ! 247: * added to an old relocation to convert it to new units; ! 248: * i.e. it is the difference between segment origins. ! 249: * (Thus if we are loading from a data segment which began at location ! 250: * 4 in a .o file into an a.out where it will be loaded starting at ! 251: * 1024, cdrel will be 1020.) ! 252: */ ! 253: long ctrel, cdrel, cbrel; ! 254: ! 255: /* ! 256: * Textbase is the start address of all text, 0 unless given by -T. ! 257: * Database is the base of all data, computed before and used during pass2. ! 258: */ ! 259: long textbase, database; ! 260: ! 261: /* ! 262: * The base addresses for the loaded text, data and bss from the ! 263: * current module during pass2 are given by torigin, dorigin and borigin. ! 264: */ ! 265: long torigin, dorigin, borigin; ! 266: ! 267: /* ! 268: * Errlev is nonzero when errors have occured. ! 269: * Delarg is an implicit argument to the routine delexit ! 270: * which is called on error. We do ``delarg = errlev'' before normal ! 271: * exits, and only if delarg is 0 (i.e. errlev was 0) do we make the ! 272: * result file executable. ! 273: */ ! 274: int errlev; ! 275: int delarg = 4; ! 276: ! 277: /* ! 278: * The biobuf structure and associated routines are used to write ! 279: * into one file at several places concurrently. Calling bopen ! 280: * with a biobuf structure sets it up to write ``biofd'' starting ! 281: * at the specified offset. You can then use ``bwrite'' and/or ``bputc'' ! 282: * to stuff characters in the stream, much like ``fwrite'' and ``fputc''. ! 283: * Calling bflush drains all the buffers and MUST be done before exit. ! 284: */ ! 285: struct biobuf { ! 286: short b_nleft; /* Number free spaces left in b_buf */ ! 287: /* Initialize to be less than BUFSIZ initially, to boundary align in file */ ! 288: char *b_ptr; /* Next place to stuff characters */ ! 289: char b_buf[BUFSIZ]; /* The buffer itself */ ! 290: off_t b_off; /* Current file offset */ ! 291: struct biobuf *b_link; /* Link in chain for bflush() */ ! 292: } *biobufs; ! 293: #define bputc(c,b) ((b)->b_nleft ? (--(b)->b_nleft, *(b)->b_ptr++ = (c)) \ ! 294: : bflushc(b, c)) ! 295: int biofd; ! 296: off_t boffset; ! 297: struct biobuf *tout, *dout, *trout, *drout, *sout, *strout; ! 298: ! 299: /* ! 300: * Offset is the current offset in the string file. ! 301: * Its initial value reflects the fact that we will ! 302: * eventually stuff the size of the string table at the ! 303: * beginning of the string table (i.e. offset itself!). ! 304: */ ! 305: off_t offset = sizeof (off_t); ! 306: ! 307: int ofilfnd; /* -o given; otherwise move l.out to a.out */ ! 308: char *ofilename = "l.out"; ! 309: int ofilemode; /* respect umask even for unsucessful ld's */ ! 310: int infil; /* current input file descriptor */ ! 311: char *filname; /* and its name */ ! 312: ! 313: /* ! 314: * Base of the string table of the current module (pass1 and pass2). ! 315: */ ! 316: char *curstr; ! 317: ! 318: /* ! 319: * System software page size, as returned by getpagesize. ! 320: */ ! 321: int pagesize; ! 322: ! 323: char get(); ! 324: int delexit(); ! 325: char *savestr(); ! 326: ! 327: main(argc, argv) ! 328: char **argv; ! 329: { ! 330: register int c, i; ! 331: int num; ! 332: register char *ap, **p; ! 333: char save; ! 334: ! 335: if (signal(SIGINT, SIG_IGN) != SIG_IGN) { ! 336: signal(SIGINT, delexit); ! 337: signal(SIGTERM, delexit); ! 338: } ! 339: if (argc == 1) ! 340: exit(4); ! 341: p = argv+1; ! 342: pagesize = getpagesize(); ! 343: ! 344: /* ! 345: * Scan files once to find where symbols are defined. ! 346: */ ! 347: for (c=1; c<argc; c++) { ! 348: if (trace) ! 349: printf("%s:\n", *p); ! 350: filname = 0; ! 351: ap = *p++; ! 352: if (*ap != '-') { ! 353: load1arg(ap); ! 354: continue; ! 355: } ! 356: for (i=1; ap[i]; i++) switch (ap[i]) { ! 357: ! 358: case 'o': ! 359: if (++c >= argc) ! 360: error(1, "-o where?"); ! 361: ofilename = *p++; ! 362: ofilfnd++; ! 363: continue; ! 364: case 'u': ! 365: case 'e': ! 366: if (++c >= argc) ! 367: error(1, "-u or -c: arg missing"); ! 368: enter(slookup(*p++)); ! 369: if (ap[i]=='e') ! 370: entrypt = lastsym; ! 371: continue; ! 372: case 'H': ! 373: if (++c >= argc) ! 374: error(1, "-H: arg missing"); ! 375: if (tsize!=0) ! 376: error(1, "-H: too late, some text already loaded"); ! 377: hsize = atoi(*p++); ! 378: continue; ! 379: case 'A': ! 380: if (++c >= argc) ! 381: error(1, "-A: arg missing"); ! 382: if (Aflag) ! 383: error(1, "-A: only one base file allowed"); ! 384: Aflag = 1; ! 385: nflag = 0; ! 386: funding = 1; ! 387: load1arg(*p++); ! 388: trsize = drsize = tsize = dsize = bsize = 0; ! 389: ctrel = cdrel = cbrel = 0; ! 390: funding = 0; ! 391: addsym = nextsym; ! 392: continue; ! 393: case 'D': ! 394: if (++c >= argc) ! 395: error(1, "-D: arg missing"); ! 396: num = htoi(*p++); ! 397: if (dsize > num) ! 398: error(1, "-D: too small"); ! 399: dsize = num; ! 400: continue; ! 401: case 'T': ! 402: if (++c >= argc) ! 403: error(1, "-T: arg missing"); ! 404: if (tsize!=0) ! 405: error(1, "-T: too late, some text already loaded"); ! 406: textbase = htoi(*p++); ! 407: continue; ! 408: case 'l': ! 409: save = ap[--i]; ! 410: ap[i]='-'; ! 411: load1arg(&ap[i]); ! 412: ap[i]=save; ! 413: goto next; ! 414: case 'M': ! 415: Mflag++; ! 416: continue; ! 417: case 'x': ! 418: xflag++; ! 419: continue; ! 420: case 'X': ! 421: Xflag++; ! 422: continue; ! 423: case 'S': ! 424: Sflag++; ! 425: continue; ! 426: case 'r': ! 427: rflag++; ! 428: arflag++; ! 429: continue; ! 430: case 's': ! 431: sflag++; ! 432: xflag++; ! 433: continue; ! 434: case 'n': ! 435: nflag++; ! 436: Nflag = zflag = 0; ! 437: continue; ! 438: case 'N': ! 439: Nflag++; ! 440: nflag = zflag = 0; ! 441: continue; ! 442: case 'd': ! 443: dflag++; ! 444: continue; ! 445: case 'i': ! 446: printf("ld: -i ignored\n"); ! 447: continue; ! 448: case 't': ! 449: trace++; ! 450: continue; ! 451: case 'y': ! 452: if (ap[i+1] == 0) ! 453: error(1, "-y: symbol name missing"); ! 454: if (yflag == 0) { ! 455: ytab = (char **)calloc(argc, sizeof (char **)); ! 456: if (ytab == 0) ! 457: error(1, "ran out of memory (-y)"); ! 458: } ! 459: ytab[yflag++] = &ap[i+1]; ! 460: goto next; ! 461: case 'z': ! 462: zflag++; ! 463: Nflag = nflag = 0; ! 464: continue; ! 465: default: ! 466: filname = savestr("-x"); /* kludge */ ! 467: filname[1] = ap[i]; /* kludge */ ! 468: archdr.ar_name[0] = 0; /* kludge */ ! 469: error(1, "bad flag"); ! 470: } ! 471: next: ! 472: ; ! 473: } ! 474: if (rflag == 0 && Nflag == 0 && nflag == 0) ! 475: zflag++; ! 476: endload(argc, argv); ! 477: exit(0); ! 478: } ! 479: ! 480: /* ! 481: * Convert a ascii string which is a hex number. ! 482: * Used by -T and -D options. ! 483: */ ! 484: htoi(p) ! 485: register char *p; ! 486: { ! 487: register int c, n; ! 488: ! 489: n = 0; ! 490: while (c = *p++) { ! 491: n <<= 4; ! 492: if (isdigit(c)) ! 493: n += c - '0'; ! 494: else if (c >= 'a' && c <= 'f') ! 495: n += 10 + (c - 'a'); ! 496: else if (c >= 'A' && c <= 'F') ! 497: n += 10 + (c - 'A'); ! 498: else ! 499: error(1, "badly formed hex number"); ! 500: } ! 501: return (n); ! 502: } ! 503: ! 504: delexit() ! 505: { ! 506: struct stat stbuf; ! 507: long size; ! 508: char c = 0; ! 509: ! 510: bflush(); ! 511: unlink("l.out"); ! 512: if (delarg==0 && Aflag==0) ! 513: chmod(ofilename, ofilemode); ! 514: /* ! 515: * We have to insure that the last block of the data segment ! 516: * is allocated a full BLKSIZE block. If the underlying ! 517: * file system allocates frags that are smaller than BLKSIZE, ! 518: * a full zero filled BLKSIZE block needs to be allocated so ! 519: * that when it is demand paged, the paged in block will be ! 520: * appropriately filled with zeros. ! 521: */ ! 522: fstat(biofd, &stbuf); ! 523: size = round(stbuf.st_size, BLKSIZE); ! 524: if (!rflag && size > stbuf.st_size) { ! 525: lseek(biofd, size - 1, 0); ! 526: write(biofd, &c, 1); ! 527: } ! 528: exit (delarg); ! 529: } ! 530: ! 531: endload(argc, argv) ! 532: int argc; ! 533: char **argv; ! 534: { ! 535: register int c, i; ! 536: long dnum; ! 537: register char *ap, **p; ! 538: ! 539: clibseg = libseg; ! 540: filname = 0; ! 541: middle(); ! 542: setupout(); ! 543: p = argv+1; ! 544: for (c=1; c<argc; c++) { ! 545: ap = *p++; ! 546: if (trace) ! 547: printf("%s:\n", ap); ! 548: if (*ap != '-') { ! 549: load2arg(ap); ! 550: continue; ! 551: } ! 552: for (i=1; ap[i]; i++) switch (ap[i]) { ! 553: ! 554: case 'D': ! 555: dnum = htoi(*p); ! 556: if (dorigin < dnum) ! 557: while (dorigin < dnum) ! 558: bputc(0, dout), dorigin++; ! 559: /* fall into ... */ ! 560: case 'T': ! 561: case 'u': ! 562: case 'e': ! 563: case 'o': ! 564: case 'H': ! 565: ++c; ! 566: ++p; ! 567: /* fall into ... */ ! 568: default: ! 569: continue; ! 570: case 'A': ! 571: funding = 1; ! 572: load2arg(*p++); ! 573: funding = 0; ! 574: c++; ! 575: continue; ! 576: case 'y': ! 577: goto next; ! 578: case 'l': ! 579: ap[--i]='-'; ! 580: load2arg(&ap[i]); ! 581: goto next; ! 582: } ! 583: next: ! 584: ; ! 585: } ! 586: finishout(); ! 587: } ! 588: ! 589: /* ! 590: * Scan file to find defined symbols. ! 591: */ ! 592: load1arg(cp) ! 593: register char *cp; ! 594: { ! 595: register struct ranlib *tp; ! 596: off_t nloc; ! 597: int kind; ! 598: ! 599: kind = getfile(cp); ! 600: if (Mflag) ! 601: printf("%s\n", filname); ! 602: switch (kind) { ! 603: ! 604: /* ! 605: * Plain file. ! 606: */ ! 607: case 0: ! 608: load1(0, 0L); ! 609: break; ! 610: ! 611: /* ! 612: * Archive without table of contents. ! 613: * (Slowly) process each member. ! 614: */ ! 615: case 1: ! 616: error(-1, ! 617: "warning: archive has no table of contents; add one using ranlib(1)"); ! 618: nloc = SARMAG; ! 619: while (step(nloc)) ! 620: nloc += sizeof(archdr) + ! 621: round(atol(archdr.ar_size), sizeof (short)); ! 622: break; ! 623: ! 624: /* ! 625: * Archive with table of contents. ! 626: * Read the table of contents and its associated string table. ! 627: * Pass through the library resolving symbols until nothing changes ! 628: * for an entire pass (i.e. you can get away with backward references ! 629: * when there is a table of contents!) ! 630: */ ! 631: case 2: ! 632: nloc = SARMAG + sizeof (archdr); ! 633: dseek(&text, nloc, sizeof (tnum)); ! 634: mget((char *)&tnum, sizeof (tnum), &text); ! 635: nloc += sizeof (tnum); ! 636: tab = (struct ranlib *)malloc(tnum); ! 637: if (tab == 0) ! 638: error(1, "ran out of memory (toc)"); ! 639: dseek(&text, nloc, tnum); ! 640: mget((char *)tab, tnum, &text); ! 641: nloc += tnum; ! 642: tnum /= sizeof (struct ranlib); ! 643: dseek(&text, nloc, sizeof (ssiz)); ! 644: mget((char *)&ssiz, sizeof (ssiz), &text); ! 645: nloc += sizeof (ssiz); ! 646: tabstr = (char *)malloc(ssiz); ! 647: if (tabstr == 0) ! 648: error(1, "ran out of memory (tocstr)"); ! 649: dseek(&text, nloc, ssiz); ! 650: mget((char *)tabstr, ssiz, &text); ! 651: for (tp = &tab[tnum]; --tp >= tab;) { ! 652: if (tp->ran_un.ran_strx < 0 || ! 653: tp->ran_un.ran_strx >= ssiz) ! 654: error(1, "mangled archive table of contents"); ! 655: tp->ran_un.ran_name = tabstr + tp->ran_un.ran_strx; ! 656: } ! 657: while (ldrand()) ! 658: continue; ! 659: cfree((char *)tab); ! 660: cfree(tabstr); ! 661: nextlibp(-1); ! 662: break; ! 663: ! 664: /* ! 665: * Table of contents is out of date, so search ! 666: * as a normal library (but skip the __.SYMDEF file). ! 667: */ ! 668: case 3: ! 669: error(-1, ! 670: "warning: table of contents for archive is out of date; rerun ranlib(1)"); ! 671: nloc = SARMAG; ! 672: do ! 673: nloc += sizeof(archdr) + ! 674: round(atol(archdr.ar_size), sizeof(short)); ! 675: while (step(nloc)); ! 676: break; ! 677: } ! 678: close(infil); ! 679: } ! 680: ! 681: /* ! 682: * Advance to the next archive member, which ! 683: * is at offset nloc in the archive. If the member ! 684: * is useful, record its location in the liblist structure ! 685: * for use in pass2. Mark the end of the archive in libilst with a -1. ! 686: */ ! 687: step(nloc) ! 688: off_t nloc; ! 689: { ! 690: ! 691: dseek(&text, nloc, (long) sizeof archdr); ! 692: if (text.size <= 0) { ! 693: nextlibp(-1); ! 694: return (0); ! 695: } ! 696: getarhdr(); ! 697: if (load1(1, nloc + (sizeof archdr))) ! 698: nextlibp(nloc); ! 699: return (1); ! 700: } ! 701: ! 702: /* ! 703: * Record the location of a useful archive member. ! 704: * Recording -1 marks the end of files from an archive. ! 705: * The liblist data structure is dynamically extended here. ! 706: */ ! 707: nextlibp(val) ! 708: off_t val; ! 709: { ! 710: ! 711: if (clibseg->li_used == NROUT) { ! 712: if (++clibseg == &libseg[NSEG]) ! 713: error(1, "too many files loaded from libraries"); ! 714: clibseg->li_first = (off_t *)malloc(NROUT * sizeof (off_t)); ! 715: if (clibseg->li_first == 0) ! 716: error(1, "ran out of memory (nextlibp)"); ! 717: } ! 718: clibseg->li_first[clibseg->li_used++] = val; ! 719: if (val != -1 && Mflag) ! 720: printf("\t%s\n", archdr.ar_name); ! 721: } ! 722: ! 723: /* ! 724: * One pass over an archive with a table of contents. ! 725: * Remember the number of symbols currently defined, ! 726: * then call step on members which look promising (i.e. ! 727: * that define a symbol which is currently externally undefined). ! 728: * Indicate to our caller whether this process netted any more symbols. ! 729: */ ! 730: ldrand() ! 731: { ! 732: register struct nlist *sp, **hp; ! 733: register struct ranlib *tp, *tplast; ! 734: off_t loc; ! 735: int nsymt = symx(nextsym); ! 736: ! 737: tplast = &tab[tnum-1]; ! 738: for (tp = tab; tp <= tplast; tp++) { ! 739: if ((hp = slookup(tp->ran_un.ran_name)) == 0) ! 740: continue; ! 741: sp = *hp; ! 742: if (sp->n_type != N_EXT+N_UNDF) ! 743: continue; ! 744: step(tp->ran_off); ! 745: loc = tp->ran_off; ! 746: while (tp < tplast && (tp+1)->ran_off == loc) ! 747: tp++; ! 748: } ! 749: return (symx(nextsym) != nsymt); ! 750: } ! 751: ! 752: /* ! 753: * Examine a single file or archive member on pass 1. ! 754: */ ! 755: load1(libflg, loc) ! 756: off_t loc; ! 757: { ! 758: register struct nlist *sp; ! 759: struct nlist *savnext; ! 760: int ndef, nlocal, type, size, nsymt; ! 761: register int i; ! 762: off_t maxoff; ! 763: struct stat stb; ! 764: ! 765: readhdr(loc); ! 766: if (filhdr.a_syms == 0) { ! 767: if (filhdr.a_text+filhdr.a_data == 0) ! 768: return (0); ! 769: error(1, "no namelist"); ! 770: } ! 771: if (libflg) ! 772: maxoff = atol(archdr.ar_size); ! 773: else { ! 774: fstat(infil, &stb); ! 775: maxoff = stb.st_size; ! 776: } ! 777: if (N_STROFF(filhdr) + sizeof (off_t) >= maxoff) ! 778: error(1, "too small (old format .o?)"); ! 779: ctrel = tsize; cdrel += dsize; cbrel += bsize; ! 780: ndef = 0; ! 781: nlocal = sizeof(cursym); ! 782: savnext = nextsym; ! 783: loc += N_SYMOFF(filhdr); ! 784: dseek(&text, loc, filhdr.a_syms); ! 785: dseek(&reloc, loc + filhdr.a_syms, sizeof(off_t)); ! 786: mget(&size, sizeof (size), &reloc); ! 787: dseek(&reloc, loc + filhdr.a_syms+sizeof (off_t), size-sizeof (off_t)); ! 788: curstr = (char *)malloc(size); ! 789: if (curstr == NULL) ! 790: error(1, "no space for string table"); ! 791: mget(curstr+sizeof(off_t), size-sizeof(off_t), &reloc); ! 792: while (text.size > 0) { ! 793: mget((char *)&cursym, sizeof(struct nlist), &text); ! 794: if (cursym.n_un.n_strx) { ! 795: if (cursym.n_un.n_strx<sizeof(size) || ! 796: cursym.n_un.n_strx>=size) ! 797: error(1, "bad string table index (pass 1)"); ! 798: cursym.n_un.n_name = curstr + cursym.n_un.n_strx; ! 799: } ! 800: type = cursym.n_type; ! 801: if ((type&N_EXT)==0) { ! 802: if (Xflag==0 || cursym.n_un.n_name[0]!='L' || ! 803: type & N_STAB) ! 804: nlocal += sizeof cursym; ! 805: continue; ! 806: } ! 807: symreloc(); ! 808: if (enter(lookup())) ! 809: continue; ! 810: if ((sp = lastsym)->n_type != N_EXT+N_UNDF) ! 811: continue; ! 812: if (cursym.n_type == N_EXT+N_UNDF) { ! 813: if (cursym.n_value > sp->n_value) ! 814: sp->n_value = cursym.n_value; ! 815: continue; ! 816: } ! 817: if (sp->n_value != 0 && cursym.n_type == N_EXT+N_TEXT) ! 818: continue; ! 819: ndef++; ! 820: sp->n_type = cursym.n_type; ! 821: sp->n_value = cursym.n_value; ! 822: } ! 823: if (libflg==0 || ndef) { ! 824: tsize += filhdr.a_text; ! 825: dsize += round(filhdr.a_data, sizeof (long)); ! 826: bsize += round(filhdr.a_bss, sizeof (long)); ! 827: ssize += nlocal; ! 828: trsize += filhdr.a_trsize; ! 829: drsize += filhdr.a_drsize; ! 830: if (funding) ! 831: textbase = (*slookup("_end"))->n_value; ! 832: nsymt = symx(nextsym); ! 833: for (i = symx(savnext); i < nsymt; i++) { ! 834: sp = xsym(i); ! 835: sp->n_un.n_name = savestr(sp->n_un.n_name); ! 836: } ! 837: free(curstr); ! 838: return (1); ! 839: } ! 840: /* ! 841: * No symbols defined by this library member. ! 842: * Rip out the hash table entries and reset the symbol table. ! 843: */ ! 844: symfree(savnext); ! 845: free(curstr); ! 846: return(0); ! 847: } ! 848: ! 849: middle() ! 850: { ! 851: register struct nlist *sp; ! 852: long csize, t, corigin, ocsize; ! 853: int nund, rnd; ! 854: char s; ! 855: register int i; ! 856: int nsymt; ! 857: ! 858: torigin = 0; ! 859: dorigin = 0; ! 860: borigin = 0; ! 861: ! 862: p_etext = *slookup("_etext"); ! 863: p_edata = *slookup("_edata"); ! 864: p_end = *slookup("_end"); ! 865: /* ! 866: * If there are any undefined symbols, save the relocation bits. ! 867: */ ! 868: nsymt = symx(nextsym); ! 869: if (rflag==0) { ! 870: for (i = 0; i < nsymt; i++) { ! 871: sp = xsym(i); ! 872: if (sp->n_type==N_EXT+N_UNDF && sp->n_value==0 && ! 873: sp!=p_end && sp!=p_edata && sp!=p_etext) { ! 874: rflag++; ! 875: dflag = 0; ! 876: break; ! 877: } ! 878: } ! 879: } ! 880: if (rflag) ! 881: sflag = zflag = 0; ! 882: /* ! 883: * Assign common locations. ! 884: */ ! 885: csize = 0; ! 886: if (!Aflag) ! 887: addsym = symseg[0].sy_first; ! 888: database = round(tsize+textbase, ! 889: (nflag||zflag? pagesize : sizeof (long))); ! 890: database += hsize; ! 891: if (dflag || rflag==0) { ! 892: ldrsym(p_etext, tsize, N_EXT+N_TEXT); ! 893: ldrsym(p_edata, dsize, N_EXT+N_DATA); ! 894: ldrsym(p_end, bsize, N_EXT+N_BSS); ! 895: for (i = symx(addsym); i < nsymt; i++) { ! 896: sp = xsym(i); ! 897: if ((s=sp->n_type)==N_EXT+N_UNDF && ! 898: (t = sp->n_value)!=0) { ! 899: if (t >= sizeof (double)) ! 900: rnd = sizeof (double); ! 901: else if (t >= sizeof (long)) ! 902: rnd = sizeof (long); ! 903: else ! 904: rnd = sizeof (short); ! 905: csize = round(csize, rnd); ! 906: sp->n_value = csize; ! 907: sp->n_type = N_EXT+N_COMM; ! 908: ocsize = csize; ! 909: csize += t; ! 910: } ! 911: if (s&N_EXT && (s&N_TYPE)==N_UNDF && s&N_STAB) { ! 912: sp->n_value = ocsize; ! 913: sp->n_type = (s&N_STAB) | (N_EXT+N_COMM); ! 914: } ! 915: } ! 916: } ! 917: /* ! 918: * Now set symbols to their final value ! 919: */ ! 920: csize = round(csize, sizeof (long)); ! 921: torigin = textbase; ! 922: dorigin = database; ! 923: corigin = dorigin + dsize; ! 924: borigin = corigin + csize; ! 925: nund = 0; ! 926: nsymt = symx(nextsym); ! 927: for (i = symx(addsym); i<nsymt; i++) { ! 928: sp = xsym(i); ! 929: switch (sp->n_type & (N_TYPE+N_EXT)) { ! 930: ! 931: case N_EXT+N_UNDF: ! 932: if (arflag == 0) ! 933: errlev |= 01; ! 934: if ((arflag==0 || dflag) && sp->n_value==0) { ! 935: if (sp==p_end || sp==p_etext || sp==p_edata) ! 936: continue; ! 937: if (nund==0) ! 938: printf("Undefined:\n"); ! 939: nund++; ! 940: printf("%s\n", sp->n_un.n_name); ! 941: } ! 942: continue; ! 943: case N_EXT+N_ABS: ! 944: default: ! 945: continue; ! 946: case N_EXT+N_TEXT: ! 947: sp->n_value += torigin; ! 948: continue; ! 949: case N_EXT+N_DATA: ! 950: sp->n_value += dorigin; ! 951: continue; ! 952: case N_EXT+N_BSS: ! 953: sp->n_value += borigin; ! 954: continue; ! 955: case N_EXT+N_COMM: ! 956: sp->n_type = (sp->n_type & N_STAB) | (N_EXT+N_BSS); ! 957: sp->n_value += corigin; ! 958: continue; ! 959: } ! 960: } ! 961: if (sflag || xflag) ! 962: ssize = 0; ! 963: bsize += csize; ! 964: nsym = ssize / (sizeof cursym); ! 965: if (Aflag) { ! 966: fixspec(p_etext,torigin); ! 967: fixspec(p_edata,dorigin); ! 968: fixspec(p_end,borigin); ! 969: } ! 970: } ! 971: ! 972: fixspec(sym,offset) ! 973: struct nlist *sym; ! 974: long offset; ! 975: { ! 976: ! 977: if(symx(sym) < symx(addsym) && sym!=0) ! 978: sym->n_value += offset; ! 979: } ! 980: ! 981: ldrsym(sp, val, type) ! 982: register struct nlist *sp; ! 983: long val; ! 984: { ! 985: ! 986: if (sp == 0) ! 987: return; ! 988: if ((sp->n_type != N_EXT+N_UNDF || sp->n_value) && !Aflag) { ! 989: printf("%s: ", sp->n_un.n_name); ! 990: error(0, "user attempt to redfine loader-defined symbol"); ! 991: return; ! 992: } ! 993: sp->n_type = type; ! 994: sp->n_value = val; ! 995: } ! 996: ! 997: off_t wroff; ! 998: struct biobuf toutb; ! 999: ! 1000: setupout() ! 1001: { ! 1002: int bss; ! 1003: extern char *sys_errlist[]; ! 1004: extern int errno; ! 1005: ! 1006: ofilemode = 0777 & ~umask(0); ! 1007: biofd = creat(ofilename, 0666 & ofilemode); ! 1008: if (biofd < 0) { ! 1009: filname = ofilename; /* kludge */ ! 1010: archdr.ar_name[0] = 0; /* kludge */ ! 1011: error(1, sys_errlist[errno]); /* kludge */ ! 1012: } else { ! 1013: struct stat mybuf; /* kls kludge */ ! 1014: fstat(biofd, &mybuf); /* suppose file exists, wrong*/ ! 1015: if(mybuf.st_mode & 0111) { /* mode, ld fails? */ ! 1016: chmod(ofilename, mybuf.st_mode & 0666); ! 1017: ofilemode = mybuf.st_mode; ! 1018: } ! 1019: } ! 1020: tout = &toutb; ! 1021: bopen(tout, 0); ! 1022: filhdr.a_magic = nflag ? NMAGIC : (zflag ? ZMAGIC : OMAGIC); ! 1023: filhdr.a_text = nflag ? tsize : ! 1024: round(tsize, zflag ? pagesize : sizeof (long)); ! 1025: filhdr.a_data = zflag ? round(dsize, pagesize) : dsize; ! 1026: bss = bsize - (filhdr.a_data - dsize); ! 1027: if (bss < 0) ! 1028: bss = 0; ! 1029: filhdr.a_bss = bss; ! 1030: filhdr.a_trsize = trsize; ! 1031: filhdr.a_drsize = drsize; ! 1032: filhdr.a_syms = sflag? 0: (ssize + (sizeof cursym)*symx(nextsym)); ! 1033: if (entrypt) { ! 1034: if (entrypt->n_type!=N_EXT+N_TEXT) ! 1035: error(0, "entry point not in text"); ! 1036: else ! 1037: filhdr.a_entry = entrypt->n_value; ! 1038: } else ! 1039: filhdr.a_entry = 0; ! 1040: filhdr.a_trsize = (rflag ? trsize:0); ! 1041: filhdr.a_drsize = (rflag ? drsize:0); ! 1042: bwrite((char *)&filhdr, sizeof (filhdr), tout); ! 1043: if (zflag) { ! 1044: bflush1(tout); ! 1045: biobufs = 0; ! 1046: bopen(tout, pagesize); ! 1047: } ! 1048: wroff = N_TXTOFF(filhdr) + filhdr.a_text; ! 1049: outb(&dout, filhdr.a_data); ! 1050: if (rflag) { ! 1051: outb(&trout, filhdr.a_trsize); ! 1052: outb(&drout, filhdr.a_drsize); ! 1053: } ! 1054: if (sflag==0 || xflag==0) { ! 1055: outb(&sout, filhdr.a_syms); ! 1056: wroff += sizeof (offset); ! 1057: outb(&strout, 0); ! 1058: } ! 1059: } ! 1060: ! 1061: outb(bp, inc) ! 1062: register struct biobuf **bp; ! 1063: { ! 1064: ! 1065: *bp = (struct biobuf *)malloc(sizeof (struct biobuf)); ! 1066: if (*bp == 0) ! 1067: error(1, "ran out of memory (outb)"); ! 1068: bopen(*bp, wroff); ! 1069: wroff += inc; ! 1070: } ! 1071: ! 1072: load2arg(acp) ! 1073: char *acp; ! 1074: { ! 1075: register char *cp; ! 1076: off_t loc; ! 1077: ! 1078: cp = acp; ! 1079: if (getfile(cp) == 0) { ! 1080: while (*cp) ! 1081: cp++; ! 1082: while (cp >= acp && *--cp != '/'); ! 1083: mkfsym(++cp); ! 1084: load2(0L); ! 1085: } else { /* scan archive members referenced */ ! 1086: for (;;) { ! 1087: if (clibseg->li_used2 == clibseg->li_used) { ! 1088: if (clibseg->li_used < NROUT) ! 1089: error(1, "libseg botch"); ! 1090: clibseg++; ! 1091: } ! 1092: loc = clibseg->li_first[clibseg->li_used2++]; ! 1093: if (loc == -1) ! 1094: break; ! 1095: dseek(&text, loc, (long)sizeof(archdr)); ! 1096: getarhdr(); ! 1097: mkfsym(archdr.ar_name); ! 1098: load2(loc + (long)sizeof(archdr)); ! 1099: } ! 1100: } ! 1101: close(infil); ! 1102: } ! 1103: ! 1104: load2(loc) ! 1105: long loc; ! 1106: { ! 1107: int size; ! 1108: register struct nlist *sp; ! 1109: register struct local *lp; ! 1110: register int symno, i; ! 1111: int type; ! 1112: ! 1113: readhdr(loc); ! 1114: if (!funding) { ! 1115: ctrel = torigin; ! 1116: cdrel += dorigin; ! 1117: cbrel += borigin; ! 1118: } ! 1119: /* ! 1120: * Reread the symbol table, recording the numbering ! 1121: * of symbols for fixing external references. ! 1122: */ ! 1123: for (i = 0; i < LHSIZ; i++) ! 1124: lochash[i] = 0; ! 1125: clocseg = locseg; ! 1126: clocseg->lo_used = 0; ! 1127: symno = -1; ! 1128: loc += N_TXTOFF(filhdr); ! 1129: dseek(&text, loc+filhdr.a_text+filhdr.a_data+ ! 1130: filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms, sizeof(off_t)); ! 1131: mget(&size, sizeof(size), &text); ! 1132: dseek(&text, loc+filhdr.a_text+filhdr.a_data+ ! 1133: filhdr.a_trsize+filhdr.a_drsize+filhdr.a_syms+sizeof(off_t), ! 1134: size - sizeof(off_t)); ! 1135: curstr = (char *)malloc(size); ! 1136: if (curstr == NULL) ! 1137: error(1, "out of space reading string table (pass 2)"); ! 1138: mget(curstr+sizeof(off_t), size-sizeof(off_t), &text); ! 1139: dseek(&text, loc+filhdr.a_text+filhdr.a_data+ ! 1140: filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms); ! 1141: while (text.size > 0) { ! 1142: symno++; ! 1143: mget((char *)&cursym, sizeof(struct nlist), &text); ! 1144: if (cursym.n_un.n_strx) { ! 1145: if (cursym.n_un.n_strx<sizeof(size) || ! 1146: cursym.n_un.n_strx>=size) ! 1147: error(1, "bad string table index (pass 2)"); ! 1148: cursym.n_un.n_name = curstr + cursym.n_un.n_strx; ! 1149: } ! 1150: /* inline expansion of symreloc() */ ! 1151: switch (cursym.n_type & 017) { ! 1152: ! 1153: case N_TEXT: ! 1154: case N_EXT+N_TEXT: ! 1155: cursym.n_value += ctrel; ! 1156: break; ! 1157: case N_DATA: ! 1158: case N_EXT+N_DATA: ! 1159: cursym.n_value += cdrel; ! 1160: break; ! 1161: case N_BSS: ! 1162: case N_EXT+N_BSS: ! 1163: cursym.n_value += cbrel; ! 1164: break; ! 1165: case N_EXT+N_UNDF: ! 1166: break; ! 1167: default: ! 1168: if (cursym.n_type&N_EXT) ! 1169: cursym.n_type = N_EXT+N_ABS; ! 1170: } ! 1171: /* end inline expansion of symreloc() */ ! 1172: type = cursym.n_type; ! 1173: if (yflag && cursym.n_un.n_name) ! 1174: for (i = 0; i < yflag; i++) ! 1175: /* fast check for 2d character! */ ! 1176: if (ytab[i][1] == cursym.n_un.n_name[1] && ! 1177: !strcmp(ytab[i], cursym.n_un.n_name)) { ! 1178: tracesym(); ! 1179: break; ! 1180: } ! 1181: if ((type&N_EXT) == 0) { ! 1182: if (!sflag&&!xflag&& ! 1183: (!Xflag||cursym.n_un.n_name[0]!='L'||type&N_STAB)) ! 1184: symwrite(&cursym, sout); ! 1185: continue; ! 1186: } ! 1187: if (funding) ! 1188: continue; ! 1189: if ((sp = *lookup()) == 0) ! 1190: error(1, "internal error: symbol not found"); ! 1191: if (cursym.n_type == N_EXT+N_UNDF) { ! 1192: if (clocseg->lo_used == NSYMPR) { ! 1193: if (++clocseg == &locseg[NSEG]) ! 1194: error(1, "local symbol overflow"); ! 1195: clocseg->lo_used = 0; ! 1196: } ! 1197: if (clocseg->lo_first == 0) { ! 1198: clocseg->lo_first = (struct local *) ! 1199: malloc(NSYMPR * sizeof (struct local)); ! 1200: if (clocseg->lo_first == 0) ! 1201: error(1, "out of memory (clocseg)"); ! 1202: } ! 1203: lp = &clocseg->lo_first[clocseg->lo_used++]; ! 1204: lp->l_index = symno; ! 1205: lp->l_symbol = sp; ! 1206: lp->l_link = lochash[symno % LHSIZ]; ! 1207: lochash[symno % LHSIZ] = lp; ! 1208: continue; ! 1209: } ! 1210: if (cursym.n_type & N_STAB) ! 1211: continue; ! 1212: if (cursym.n_type!=sp->n_type || cursym.n_value!=sp->n_value) { ! 1213: printf("%s: ", cursym.n_un.n_name); ! 1214: error(0, "multiply defined"); ! 1215: } ! 1216: } ! 1217: if (funding) ! 1218: return; ! 1219: dseek(&text, loc, filhdr.a_text); ! 1220: dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize); ! 1221: load2td(ctrel, torigin - textbase, tout, trout); ! 1222: dseek(&text, loc+filhdr.a_text, filhdr.a_data); ! 1223: dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize, ! 1224: filhdr.a_drsize); ! 1225: load2td(cdrel, dorigin - database, dout, drout); ! 1226: while (filhdr.a_data & (sizeof(long)-1)) { ! 1227: bputc(0, dout); ! 1228: filhdr.a_data++; ! 1229: } ! 1230: torigin += filhdr.a_text; ! 1231: dorigin += round(filhdr.a_data, sizeof (long)); ! 1232: borigin += round(filhdr.a_bss, sizeof (long)); ! 1233: free(curstr); ! 1234: } ! 1235: ! 1236: struct tynames { ! 1237: int ty_value; ! 1238: char *ty_name; ! 1239: } tynames[] = { ! 1240: N_UNDF, "undefined", ! 1241: N_ABS, "absolute", ! 1242: N_TEXT, "text", ! 1243: N_DATA, "data", ! 1244: N_BSS, "bss", ! 1245: N_COMM, "common", ! 1246: 0, 0, ! 1247: }; ! 1248: ! 1249: tracesym() ! 1250: { ! 1251: register struct tynames *tp; ! 1252: ! 1253: if (cursym.n_type & N_STAB) ! 1254: return; ! 1255: printf("%s", filname); ! 1256: if (archdr.ar_name[0]) ! 1257: printf("(%s)", archdr.ar_name); ! 1258: printf(": "); ! 1259: if ((cursym.n_type&N_TYPE) == N_UNDF && cursym.n_value) { ! 1260: printf("definition of common %s size %d\n", ! 1261: cursym.n_un.n_name, cursym.n_value); ! 1262: return; ! 1263: } ! 1264: for (tp = tynames; tp->ty_name; tp++) ! 1265: if (tp->ty_value == (cursym.n_type&N_TYPE)) ! 1266: break; ! 1267: printf((cursym.n_type&N_TYPE) ? "definition of" : "reference to"); ! 1268: if (cursym.n_type&N_EXT) ! 1269: printf(" external"); ! 1270: if (tp->ty_name) ! 1271: printf(" %s", tp->ty_name); ! 1272: printf(" %s\n", cursym.n_un.n_name); ! 1273: } ! 1274: ! 1275: /* ! 1276: * This routine relocates the single text or data segment argument. ! 1277: * Offsets from external symbols are resolved by adding the value ! 1278: * of the external symbols. Non-external reference are updated to account ! 1279: * for the relative motion of the segments (ctrel, cdrel, ...). If ! 1280: * a relocation was pc-relative, then we update it to reflect the ! 1281: * change in the positioning of the segments by adding the displacement ! 1282: * of the referenced segment and subtracting the displacement of the ! 1283: * current segment (creloc). ! 1284: * ! 1285: * If we are saving the relocation information, then we increase ! 1286: * each relocation datum address by our base position in the new segment. ! 1287: */ ! 1288: load2td(creloc, position, b1, b2) ! 1289: long creloc, offset; ! 1290: struct biobuf *b1, *b2; ! 1291: { ! 1292: register struct nlist *sp; ! 1293: register struct local *lp; ! 1294: long tw; ! 1295: register struct relocation_info *rp, *rpend; ! 1296: struct relocation_info *relp; ! 1297: char *codep; ! 1298: register char *cp; ! 1299: int relsz, codesz; ! 1300: ! 1301: relsz = reloc.size; ! 1302: relp = (struct relocation_info *)malloc(relsz); ! 1303: codesz = text.size; ! 1304: codep = (char *)malloc(codesz); ! 1305: if (relp == 0 || codep == 0) ! 1306: error(1, "out of memory (load2td)"); ! 1307: mget((char *)relp, relsz, &reloc); ! 1308: rpend = &relp[relsz / sizeof (struct relocation_info)]; ! 1309: mget(codep, codesz, &text); ! 1310: for (rp = relp; rp < rpend; rp++) { ! 1311: cp = codep + rp->r_address; ! 1312: /* ! 1313: * Pick up previous value at location to be relocated. ! 1314: */ ! 1315: switch (rp->r_length) { ! 1316: ! 1317: case 0: /* byte */ ! 1318: tw = *cp; ! 1319: break; ! 1320: ! 1321: case 1: /* word */ ! 1322: tw = *(short *)cp; ! 1323: break; ! 1324: ! 1325: case 2: /* long */ ! 1326: tw = *(long *)cp; ! 1327: break; ! 1328: ! 1329: default: ! 1330: error(1, "load2td botch: bad length"); ! 1331: } ! 1332: /* ! 1333: * If relative to an external which is defined, ! 1334: * resolve to a simpler kind of reference in the ! 1335: * result file. If the external is undefined, just ! 1336: * convert the symbol number to the number of the ! 1337: * symbol in the result file and leave it undefined. ! 1338: */ ! 1339: if (rp->r_extern) { ! 1340: /* ! 1341: * Search the hash table which maps local ! 1342: * symbol numbers to symbol tables entries ! 1343: * in the new a.out file. ! 1344: */ ! 1345: lp = lochash[rp->r_symbolnum % LHSIZ]; ! 1346: while (lp->l_index != rp->r_symbolnum) { ! 1347: lp = lp->l_link; ! 1348: if (lp == 0) ! 1349: error(1, "local symbol botch"); ! 1350: } ! 1351: sp = lp->l_symbol; ! 1352: if (sp->n_type == N_EXT+N_UNDF) ! 1353: rp->r_symbolnum = nsym+symx(sp); ! 1354: else { ! 1355: rp->r_symbolnum = sp->n_type & N_TYPE; ! 1356: tw += sp->n_value; ! 1357: rp->r_extern = 0; ! 1358: } ! 1359: } else switch (rp->r_symbolnum & N_TYPE) { ! 1360: /* ! 1361: * Relocation is relative to the loaded position ! 1362: * of another segment. Update by the change in position ! 1363: * of that segment. ! 1364: */ ! 1365: case N_TEXT: ! 1366: tw += ctrel; ! 1367: break; ! 1368: case N_DATA: ! 1369: tw += cdrel; ! 1370: break; ! 1371: case N_BSS: ! 1372: tw += cbrel; ! 1373: break; ! 1374: case N_ABS: ! 1375: break; ! 1376: default: ! 1377: error(1, "relocation format botch (symbol type))"); ! 1378: } ! 1379: /* ! 1380: * Relocation is pc relative, so decrease the relocation ! 1381: * by the amount the current segment is displaced. ! 1382: * (E.g if we are a relative reference to a text location ! 1383: * from data space, we added the increase in the text address ! 1384: * above, and subtract the increase in our (data) address ! 1385: * here, leaving the net change the relative change in the ! 1386: * positioning of our text and data segments.) ! 1387: */ ! 1388: if (rp->r_pcrel) ! 1389: tw -= creloc; ! 1390: /* ! 1391: * Put the value back in the segment, ! 1392: * while checking for overflow. ! 1393: */ ! 1394: switch (rp->r_length) { ! 1395: ! 1396: case 0: /* byte */ ! 1397: if (tw < -128 || tw > 127) ! 1398: error(0, "byte displacement overflow"); ! 1399: *cp = tw; ! 1400: break; ! 1401: case 1: /* word */ ! 1402: if (tw < -32768 || tw > 32767) ! 1403: error(0, "word displacement overflow"); ! 1404: *(short *)cp = tw; ! 1405: break; ! 1406: case 2: /* long */ ! 1407: *(long *)cp = tw; ! 1408: break; ! 1409: } ! 1410: /* ! 1411: * If we are saving relocation information, ! 1412: * we must convert the address in the segment from ! 1413: * the old .o file into an address in the segment in ! 1414: * the new a.out, by adding the position of our ! 1415: * segment in the new larger segment. ! 1416: */ ! 1417: if (rflag) ! 1418: rp->r_address += position; ! 1419: } ! 1420: bwrite(codep, codesz, b1); ! 1421: if (rflag) ! 1422: bwrite(relp, relsz, b2); ! 1423: cfree((char *)relp); ! 1424: cfree(codep); ! 1425: } ! 1426: ! 1427: finishout() ! 1428: { ! 1429: register int i; ! 1430: int nsymt; ! 1431: ! 1432: if (sflag==0) { ! 1433: nsymt = symx(nextsym); ! 1434: for (i = 0; i < nsymt; i++) ! 1435: symwrite(xsym(i), sout); ! 1436: bwrite(&offset, sizeof offset, sout); ! 1437: } ! 1438: if (!ofilfnd) { ! 1439: unlink("a.out"); ! 1440: if (link("l.out", "a.out") < 0) ! 1441: error(1, "cannot move l.out to a.out"); ! 1442: ofilename = "a.out"; ! 1443: } ! 1444: delarg = errlev; ! 1445: delexit(); ! 1446: } ! 1447: ! 1448: mkfsym(s) ! 1449: char *s; ! 1450: { ! 1451: ! 1452: if (sflag || xflag) ! 1453: return; ! 1454: cursym.n_un.n_name = s; ! 1455: cursym.n_type = N_TEXT; ! 1456: cursym.n_value = torigin; ! 1457: symwrite(&cursym, sout); ! 1458: } ! 1459: ! 1460: getarhdr() ! 1461: { ! 1462: register char *cp; ! 1463: ! 1464: mget((char *)&archdr, sizeof archdr, &text); ! 1465: for (cp=archdr.ar_name; cp<&archdr.ar_name[sizeof(archdr.ar_name)];) ! 1466: if (*cp++ == ' ') { ! 1467: cp[-1] = 0; ! 1468: return; ! 1469: } ! 1470: } ! 1471: ! 1472: mget(loc, n, sp) ! 1473: register STREAM *sp; ! 1474: register char *loc; ! 1475: { ! 1476: register char *p; ! 1477: register int take; ! 1478: ! 1479: top: ! 1480: if (n == 0) ! 1481: return; ! 1482: if (sp->size && sp->nibuf) { ! 1483: p = sp->ptr; ! 1484: take = sp->size; ! 1485: if (take > sp->nibuf) ! 1486: take = sp->nibuf; ! 1487: if (take > n) ! 1488: take = n; ! 1489: n -= take; ! 1490: sp->size -= take; ! 1491: sp->nibuf -= take; ! 1492: sp->pos += take; ! 1493: do ! 1494: *loc++ = *p++; ! 1495: while (--take > 0); ! 1496: sp->ptr = p; ! 1497: goto top; ! 1498: } ! 1499: if (n > BUFSIZ) { ! 1500: take = n - n % BLKSIZE; ! 1501: lseek(infil, (sp->bno+1)*BLKSIZE, 0); ! 1502: if (take > sp->size || read(infil, loc, take) != take) ! 1503: error(1, "premature EOF"); ! 1504: loc += take; ! 1505: n -= take; ! 1506: sp->size -= take; ! 1507: sp->pos += take; ! 1508: dseek(sp, (sp->bno+1+take/BLKSIZE)*BLKSIZE, -1); ! 1509: goto top; ! 1510: } ! 1511: *loc++ = get(sp); ! 1512: --n; ! 1513: goto top; ! 1514: } ! 1515: ! 1516: symwrite(sp, bp) ! 1517: struct nlist *sp; ! 1518: struct biobuf *bp; ! 1519: { ! 1520: register int len; ! 1521: register char *str; ! 1522: ! 1523: str = sp->n_un.n_name; ! 1524: if (str) { ! 1525: sp->n_un.n_strx = offset; ! 1526: len = strlen(str) + 1; ! 1527: bwrite(str, len, strout); ! 1528: offset += len; ! 1529: } ! 1530: bwrite(sp, sizeof (*sp), bp); ! 1531: sp->n_un.n_name = str; ! 1532: } ! 1533: ! 1534: dseek(sp, loc, s) ! 1535: register STREAM *sp; ! 1536: long loc, s; ! 1537: { ! 1538: register PAGE *p; ! 1539: register b, o; ! 1540: int n; ! 1541: ! 1542: b = loc>>BLKSHIFT; ! 1543: o = loc&BLKMASK; ! 1544: if (o&01) ! 1545: error(1, "loader error; odd offset"); ! 1546: --sp->pno->nuser; ! 1547: if ((p = &page[0])->bno!=b && (p = &page[1])->bno!=b) ! 1548: if (p->nuser==0 || (p = &page[0])->nuser==0) { ! 1549: if (page[0].nuser==0 && page[1].nuser==0) ! 1550: if (page[0].bno < page[1].bno) ! 1551: p = &page[0]; ! 1552: p->bno = b; ! 1553: lseek(infil, loc & ~(long)BLKMASK, 0); ! 1554: if ((n = read(infil, p->buff, sizeof(p->buff))) < 0) ! 1555: n = 0; ! 1556: p->nibuf = n; ! 1557: } else ! 1558: error(1, "botch: no pages"); ! 1559: ++p->nuser; ! 1560: sp->bno = b; ! 1561: sp->pno = p; ! 1562: if (s != -1) {sp->size = s; sp->pos = 0;} ! 1563: sp->ptr = (char *)(p->buff + o); ! 1564: if ((sp->nibuf = p->nibuf-o) <= 0) ! 1565: sp->size = 0; ! 1566: } ! 1567: ! 1568: char ! 1569: get(asp) ! 1570: STREAM *asp; ! 1571: { ! 1572: register STREAM *sp; ! 1573: ! 1574: sp = asp; ! 1575: if ((sp->nibuf -= sizeof(char)) < 0) { ! 1576: dseek(sp, ((long)(sp->bno+1)<<BLKSHIFT), (long)-1); ! 1577: sp->nibuf -= sizeof(char); ! 1578: } ! 1579: if ((sp->size -= sizeof(char)) <= 0) { ! 1580: if (sp->size < 0) ! 1581: error(1, "premature EOF"); ! 1582: ++fpage.nuser; ! 1583: --sp->pno->nuser; ! 1584: sp->pno = (PAGE *) &fpage; ! 1585: } ! 1586: sp->pos += sizeof(char); ! 1587: return(*sp->ptr++); ! 1588: } ! 1589: ! 1590: getfile(acp) ! 1591: char *acp; ! 1592: { ! 1593: register char *cp; ! 1594: register int c; ! 1595: char arcmag[SARMAG+1]; ! 1596: struct stat stb; ! 1597: ! 1598: cp = acp; ! 1599: infil = -1; ! 1600: archdr.ar_name[0] = '\0'; ! 1601: filname = cp; ! 1602: if (cp[0]=='-' && cp[1]=='l') { ! 1603: char *locfilname = "/usr/local/lib/libxxxxxxxxxxxxxxx"; ! 1604: if(cp[2] == '\0') ! 1605: cp = "-la"; ! 1606: filname = "/usr/lib/libxxxxxxxxxxxxxxx"; ! 1607: for(c=0; cp[c+2]; c++) { ! 1608: filname[c+12] = cp[c+2]; ! 1609: locfilname[c+18] = cp[c+2]; ! 1610: } ! 1611: filname[c+12] = locfilname[c+18] = '.'; ! 1612: filname[c+13] = locfilname[c+19] = 'a'; ! 1613: filname[c+14] = locfilname[c+20] = '\0'; ! 1614: if ((infil = open(filname+4, 0)) >= 0) { ! 1615: filname += 4; ! 1616: } else if ((infil = open(filname, 0)) < 0) { ! 1617: filname = locfilname; ! 1618: } ! 1619: } ! 1620: if (infil == -1 && (infil = open(filname, 0)) < 0) ! 1621: error(1, "cannot open"); ! 1622: page[0].bno = page[1].bno = -1; ! 1623: page[0].nuser = page[1].nuser = 0; ! 1624: text.pno = reloc.pno = (PAGE *) &fpage; ! 1625: fpage.nuser = 2; ! 1626: dseek(&text, 0L, SARMAG); ! 1627: if (text.size <= 0) ! 1628: error(1, "premature EOF"); ! 1629: mget((char *)arcmag, SARMAG, &text); ! 1630: arcmag[SARMAG] = 0; ! 1631: if (strcmp(arcmag, ARMAG)) ! 1632: return (0); ! 1633: dseek(&text, SARMAG, sizeof archdr); ! 1634: if(text.size <= 0) ! 1635: return (1); ! 1636: getarhdr(); ! 1637: if (strncmp(archdr.ar_name, "__.SYMDEF", sizeof(archdr.ar_name)) != 0) ! 1638: return (1); ! 1639: fstat(infil, &stb); ! 1640: return (stb.st_mtime > atol(archdr.ar_date) ? 3 : 2); ! 1641: } ! 1642: ! 1643: struct nlist ** ! 1644: lookup() ! 1645: { ! 1646: register int sh; ! 1647: register struct nlist **hp; ! 1648: register char *cp, *cp1; ! 1649: register struct symseg *gp; ! 1650: register int i; ! 1651: ! 1652: sh = 0; ! 1653: for (cp = cursym.n_un.n_name; *cp;) ! 1654: sh = (sh<<1) + *cp++; ! 1655: sh = (sh & 0x7fffffff) % HSIZE; ! 1656: for (gp = symseg; gp < &symseg[NSEG]; gp++) { ! 1657: if (gp->sy_first == 0) { ! 1658: gp->sy_first = (struct nlist *) ! 1659: calloc(NSYM, sizeof (struct nlist)); ! 1660: gp->sy_hfirst = (struct nlist **) ! 1661: calloc(HSIZE, sizeof (struct nlist *)); ! 1662: if (gp->sy_first == 0 || gp->sy_hfirst == 0) ! 1663: error(1, "ran out of space for symbol table"); ! 1664: gp->sy_last = gp->sy_first + NSYM; ! 1665: gp->sy_hlast = gp->sy_hfirst + HSIZE; ! 1666: } ! 1667: if (gp > csymseg) ! 1668: csymseg = gp; ! 1669: hp = gp->sy_hfirst + sh; ! 1670: i = 1; ! 1671: do { ! 1672: if (*hp == 0) { ! 1673: if (gp->sy_used == NSYM) ! 1674: break; ! 1675: return (hp); ! 1676: } ! 1677: cp1 = (*hp)->n_un.n_name; ! 1678: for (cp = cursym.n_un.n_name; *cp == *cp1++;) ! 1679: if (*cp++ == 0) ! 1680: return (hp); ! 1681: hp += i; ! 1682: i += 2; ! 1683: if (hp >= gp->sy_hlast) ! 1684: hp -= HSIZE; ! 1685: } while (i < HSIZE); ! 1686: if (i > HSIZE) ! 1687: error(1, "hash table botch"); ! 1688: } ! 1689: error(1, "symbol table overflow"); ! 1690: /*NOTREACHED*/ ! 1691: } ! 1692: ! 1693: symfree(saved) ! 1694: struct nlist *saved; ! 1695: { ! 1696: register struct symseg *gp; ! 1697: register struct nlist *sp; ! 1698: ! 1699: for (gp = csymseg; gp >= symseg; gp--, csymseg--) { ! 1700: sp = gp->sy_first + gp->sy_used; ! 1701: if (sp == saved) { ! 1702: nextsym = sp; ! 1703: return; ! 1704: } ! 1705: for (sp--; sp >= gp->sy_first; sp--) { ! 1706: gp->sy_hfirst[sp->n_hash] = 0; ! 1707: gp->sy_used--; ! 1708: if (sp == saved) { ! 1709: nextsym = sp; ! 1710: return; ! 1711: } ! 1712: } ! 1713: } ! 1714: if (saved == 0) ! 1715: return; ! 1716: error(1, "symfree botch"); ! 1717: } ! 1718: ! 1719: struct nlist ** ! 1720: slookup(s) ! 1721: char *s; ! 1722: { ! 1723: ! 1724: cursym.n_un.n_name = s; ! 1725: cursym.n_type = N_EXT+N_UNDF; ! 1726: cursym.n_value = 0; ! 1727: return (lookup()); ! 1728: } ! 1729: ! 1730: enter(hp) ! 1731: register struct nlist **hp; ! 1732: { ! 1733: register struct nlist *sp; ! 1734: ! 1735: if (*hp==0) { ! 1736: if (hp < csymseg->sy_hfirst || hp >= csymseg->sy_hlast) ! 1737: error(1, "enter botch"); ! 1738: *hp = lastsym = sp = csymseg->sy_first + csymseg->sy_used; ! 1739: csymseg->sy_used++; ! 1740: sp->n_un.n_name = cursym.n_un.n_name; ! 1741: sp->n_type = cursym.n_type; ! 1742: sp->n_hash = hp - csymseg->sy_hfirst; ! 1743: sp->n_value = cursym.n_value; ! 1744: nextsym = lastsym + 1; ! 1745: return(1); ! 1746: } else { ! 1747: lastsym = *hp; ! 1748: return(0); ! 1749: } ! 1750: } ! 1751: ! 1752: symx(sp) ! 1753: struct nlist *sp; ! 1754: { ! 1755: register struct symseg *gp; ! 1756: ! 1757: if (sp == 0) ! 1758: return (0); ! 1759: for (gp = csymseg; gp >= symseg; gp--) ! 1760: /* <= is sloppy so nextsym will always work */ ! 1761: if (sp >= gp->sy_first && sp <= gp->sy_last) ! 1762: return ((gp - symseg) * NSYM + sp - gp->sy_first); ! 1763: error(1, "symx botch"); ! 1764: /*NOTREACHED*/ ! 1765: } ! 1766: ! 1767: symreloc() ! 1768: { ! 1769: if(funding) return; ! 1770: switch (cursym.n_type & 017) { ! 1771: ! 1772: case N_TEXT: ! 1773: case N_EXT+N_TEXT: ! 1774: cursym.n_value += ctrel; ! 1775: return; ! 1776: ! 1777: case N_DATA: ! 1778: case N_EXT+N_DATA: ! 1779: cursym.n_value += cdrel; ! 1780: return; ! 1781: ! 1782: case N_BSS: ! 1783: case N_EXT+N_BSS: ! 1784: cursym.n_value += cbrel; ! 1785: return; ! 1786: ! 1787: case N_EXT+N_UNDF: ! 1788: return; ! 1789: ! 1790: default: ! 1791: if (cursym.n_type&N_EXT) ! 1792: cursym.n_type = N_EXT+N_ABS; ! 1793: return; ! 1794: } ! 1795: } ! 1796: ! 1797: error(n, s) ! 1798: char *s; ! 1799: { ! 1800: ! 1801: if (errlev==0) ! 1802: printf("ld:"); ! 1803: if (filname) { ! 1804: printf("%s", filname); ! 1805: if (n != -1 && archdr.ar_name[0]) ! 1806: printf("(%s)", archdr.ar_name); ! 1807: printf(": "); ! 1808: } ! 1809: printf("%s\n", s); ! 1810: if (n == -1) ! 1811: return; ! 1812: if (n) ! 1813: delexit(); ! 1814: errlev = 2; ! 1815: } ! 1816: ! 1817: readhdr(loc) ! 1818: off_t loc; ! 1819: { ! 1820: ! 1821: dseek(&text, loc, (long)sizeof(filhdr)); ! 1822: mget((short *)&filhdr, sizeof(filhdr), &text); ! 1823: if (N_BADMAG(filhdr)) { ! 1824: if (filhdr.a_magic == OARMAG) ! 1825: error(1, "old archive"); ! 1826: error(1, "bad magic number"); ! 1827: } ! 1828: if (filhdr.a_text&01 || filhdr.a_data&01) ! 1829: error(1, "text/data size odd"); ! 1830: if (filhdr.a_magic == NMAGIC || filhdr.a_magic == ZMAGIC) { ! 1831: cdrel = -round(filhdr.a_text, pagesize); ! 1832: cbrel = cdrel - filhdr.a_data; ! 1833: } else if (filhdr.a_magic == OMAGIC) { ! 1834: cdrel = -filhdr.a_text; ! 1835: cbrel = cdrel - filhdr.a_data; ! 1836: } else ! 1837: error(1, "bad format"); ! 1838: } ! 1839: ! 1840: round(v, r) ! 1841: int v; ! 1842: u_long r; ! 1843: { ! 1844: ! 1845: r--; ! 1846: v += r; ! 1847: v &= ~(long)r; ! 1848: return(v); ! 1849: } ! 1850: ! 1851: #define NSAVETAB 8192 ! 1852: char *savetab; ! 1853: int saveleft; ! 1854: ! 1855: char * ! 1856: savestr(cp) ! 1857: register char *cp; ! 1858: { ! 1859: register int len; ! 1860: ! 1861: len = strlen(cp) + 1; ! 1862: if (len > saveleft) { ! 1863: saveleft = NSAVETAB; ! 1864: if (len > saveleft) ! 1865: saveleft = len; ! 1866: savetab = (char *)malloc(saveleft); ! 1867: if (savetab == 0) ! 1868: error(1, "ran out of memory (savestr)"); ! 1869: } ! 1870: strncpy(savetab, cp, len); ! 1871: cp = savetab; ! 1872: savetab += len; ! 1873: saveleft -= len; ! 1874: return (cp); ! 1875: } ! 1876: ! 1877: bopen(bp, off) ! 1878: struct biobuf *bp; ! 1879: { ! 1880: ! 1881: bp->b_ptr = bp->b_buf; ! 1882: bp->b_nleft = BUFSIZ - off % BUFSIZ; ! 1883: bp->b_off = off; ! 1884: bp->b_link = biobufs; ! 1885: biobufs = bp; ! 1886: } ! 1887: ! 1888: int bwrerror; ! 1889: ! 1890: bwrite(p, cnt, bp) ! 1891: register char *p; ! 1892: register int cnt; ! 1893: register struct biobuf *bp; ! 1894: { ! 1895: register int put; ! 1896: register char *to; ! 1897: ! 1898: top: ! 1899: if (cnt == 0) ! 1900: return; ! 1901: if (bp->b_nleft) { ! 1902: put = bp->b_nleft; ! 1903: if (put > cnt) ! 1904: put = cnt; ! 1905: bp->b_nleft -= put; ! 1906: to = bp->b_ptr; ! 1907: asm("movc3 r8,(r11),(r7)"); ! 1908: bp->b_ptr += put; ! 1909: p += put; ! 1910: cnt -= put; ! 1911: goto top; ! 1912: } ! 1913: if (cnt >= BUFSIZ) { ! 1914: if (bp->b_ptr != bp->b_buf) ! 1915: bflush1(bp); ! 1916: put = cnt - cnt % BUFSIZ; ! 1917: if (boffset != bp->b_off) ! 1918: lseek(biofd, bp->b_off, 0); ! 1919: if (write(biofd, p, put) != put) { ! 1920: bwrerror = 1; ! 1921: error(1, "output write error"); ! 1922: } ! 1923: bp->b_off += put; ! 1924: boffset = bp->b_off; ! 1925: p += put; ! 1926: cnt -= put; ! 1927: goto top; ! 1928: } ! 1929: bflush1(bp); ! 1930: goto top; ! 1931: } ! 1932: ! 1933: bflush() ! 1934: { ! 1935: register struct biobuf *bp; ! 1936: ! 1937: if (bwrerror) ! 1938: return; ! 1939: for (bp = biobufs; bp; bp = bp->b_link) ! 1940: bflush1(bp); ! 1941: } ! 1942: ! 1943: bflush1(bp) ! 1944: register struct biobuf *bp; ! 1945: { ! 1946: register int cnt = bp->b_ptr - bp->b_buf; ! 1947: ! 1948: if (cnt == 0) ! 1949: return; ! 1950: if (boffset != bp->b_off) ! 1951: lseek(biofd, bp->b_off, 0); ! 1952: if (write(biofd, bp->b_buf, cnt) != cnt) { ! 1953: bwrerror = 1; ! 1954: error(1, "output write error"); ! 1955: } ! 1956: bp->b_off += cnt; ! 1957: boffset = bp->b_off; ! 1958: bp->b_ptr = bp->b_buf; ! 1959: bp->b_nleft = BUFSIZ; ! 1960: } ! 1961: ! 1962: bflushc(bp, c) ! 1963: register struct biobuf *bp; ! 1964: { ! 1965: ! 1966: bflush1(bp); ! 1967: bputc(c, bp); ! 1968: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.