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

Defined functions

bflush defined in line 2013; used 1 times
bflush1 defined in line 2023; used 5 times
bflushc defined in line 2042; used 1 times
bopen defined in line 1954; used 2 times
bseek defined in line 2050; used 1 times
bwrite defined in line 1970; used 6 times
delexit defined in line 545; used 5 times
dseek defined in line 1573; used 21 times
endload defined in line 573; used 1 times
enter defined in line 1807; used 2 times
error defined in line 1874; used 67 times
finishout defined in line 1466; used 1 times
fixspec defined in line 1015; used 3 times
get defined in line 1607; used 2 times
getarhdr defined in line 1499; used 3 times
getfile defined in line 1629; used 2 times
htoi defined in line 525; used 3 times
ldrand defined in line 773; used 1 times
ldrsym defined in line 1024; used 3 times
libopen defined in line 1690; used 1 times
load1 defined in line 798; used 2 times
load1arg defined in line 635; used 3 times
load2 defined in line 1143; used 2 times
load2arg defined in line 1111; used 3 times
load2td defined in line 1327; used 2 times
lookup defined in line 1720; used 4 times
main defined in line 348; never used
mget defined in line 1511; used 15 times
middle defined in line 892; used 1 times
mkfsym defined in line 1487; used 2 times
nextlibp defined in line 750; used 3 times
outb defined in line 1100; used 5 times
readhdr defined in line 1894; used 2 times
round defined in line 1917; used 13 times
savestr defined in line 1932; used 3 times
setupout defined in line 1043; used 1 times
slookup defined in line 1796; used 7 times
step defined in line 730; used 3 times
symfree defined in line 1770; used 1 times
symreloc defined in line 1844; used 1 times
symwrite defined in line 1555; used 3 times
symx defined in line 1829; used 13 times
tracesym defined in line 1288; used 1 times

Defined variables

Aflag defined in line 247; used 6 times
Mflag defined in line 242; used 3 times
Nflag defined in line 248; used 4 times
Sflag defined in line 238; used 1 times
Xflag defined in line 237; used 3 times
addsym defined in line 120; used 5 times
archdr defined in line 229; used 28 times
arflag defined in line 240; used 3 times
biobufs defined in line 307; used 3 times
biofd defined in line 310; used 10 times
borigin defined in line 279; used 6 times
bwrerror defined in line 1968; used 3 times
cbrel defined in line 267; used 8 times
cdrel defined in line 267; used 11 times
copyright defined in line 8; never used
csymseg defined in line 96; used 11 times
ctrel defined in line 267; used 7 times
curstr defined in line 336; used 11 times
cursym defined in line 117; used 68 times
database defined in line 273; used 4 times
delarg defined in line 289; used 4 times
dflag defined in line 244; used 4 times
dirs defined in line 330; used 5 times
dorigin defined in line 279; used 11 times
dout defined in line 312; used 4 times
drout defined in line 312; used 2 times
entrypt defined in line 125; used 4 times
errlev defined in line 288; used 4 times
filhdr defined in line 228; used 78 times
filname defined in line 326; used 15 times
funding defined in line 249; used 9 times
hsize defined in line 246; used 2 times
infil defined in line 325; used 11 times
lastsym defined in line 118; used 5 times
lhinit defined in line 158; used 1 times
libseg defined in line 139; used 3 times
lochash defined in line 158; used 4 times
locseg defined in line 162; used 2 times
ndir defined in line 331; used 6 times
nextsym defined in line 119; used 12 times
nflag defined in line 243; used 8 times
nsym defined in line 121; used 2 times
ofilemode defined in line 324; used 4 times
ofilename defined in line 323; used 6 times
ofilfnd defined in line 322; used 2 times
p_blkmask defined in line 204; used 3 times
p_blkshift defined in line 203; used 7 times
p_blksize defined in line 202; used 7 times
p_edata defined in line 125; used 5 times
p_end defined in line 125; used 5 times
p_etext defined in line 125; used 5 times
pagesize defined in line 341; used 7 times
rflag defined in line 239; used 12 times
saveleft defined in line 1930; used 6 times
savetab defined in line 1929; used 5 times
sccsid defined in line 14; never used
sflag defined in line 241; used 8 times
sout defined in line 312; used 5 times
ssiz defined in line 179; used 8 times
strout defined in line 312; used 2 times
symseg defined in line 96; used 7 times
tab defined in line 180; used 8 times
tabstr defined in line 181; used 5 times
textbase defined in line 273; used 5 times
tnum defined in line 178; used 11 times
torigin defined in line 279; used 8 times
tout defined in line 312; used 5 times
toutb defined in line 1041; used 1 times
trace defined in line 235; used 3 times
trout defined in line 312; used 2 times
tynames defined in line 1278; used 1 times
xflag defined in line 236; used 6 times
yflag defined in line 250; used 4 times
ytab defined in line 251; used 5 times
zflag defined in line 245; used 10 times

Defined struct's

biobuf defined in line 299; used 28 times
libseg defined in line 135; never used
local defined in line 154; used 12 times
locseg defined in line 159; never used
symseg defined in line 90; used 6 times
tynames defined in line 1275; used 2 times

Defined macros

BLKSIZE defined in line 191; used 1 times
HSIZE defined in line 107; used 6 times
LHSIZ defined in line 153; used 5 times
NDEFDIRS defined in line 329; used 1 times
NDIRS defined in line 328; used 2 times
NROUT defined in line 74; used 4 times
NSAVETAB defined in line 1928; used 1 times
NSEG defined in line 72; used 6 times
NSYM defined in line 73; used 7 times
NSYMPR defined in line 75; used 3 times
OARMAG defined in line 230; used 1 times
bputc defined in line 308; used 3 times
xsym defined in line 114; used 5 times
Last modified: 1986-01-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4088
Valid CSS Valid XHTML 1.0 Strict