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