1: # 2: /* 3: * link editor 4: */ 5: 6: #define SIGINT 2 7: #define ARCMAGIC 0177555 8: #define FMAGIC 0407 9: #define NMAGIC 0410 10: #define IMAGIC 0411 11: 12: #define EXTERN 040 13: #define UNDEF 00 14: #define ABS 01 15: #define TEXT 02 16: #define DATA 03 17: #define BSS 04 18: #define COMM 05 /* internal use only */ 19: 20: #define RABS 00 21: #define RTEXT 02 22: #define RDATA 04 23: #define RBSS 06 24: #define REXT 010 25: 26: #define RELFLG 01 27: #define NROUT 256 28: #define NSYM 501 29: #define NSYMPR 500 30: 31: #define RONLY 0400 32: 33: char premeof[] "Premature EOF on %s"; 34: 35: struct page { 36: int nuser; 37: int bno; 38: int nibuf; 39: int buff[256]; 40: } page[2]; 41: 42: struct { 43: int nuser; 44: int bno; 45: } fpage; 46: 47: struct stream { 48: int *ptr; 49: int bno; 50: int nibuf; 51: int size; 52: struct page *pno; 53: }; 54: 55: struct stream text; 56: struct stream reloc; 57: 58: struct archdr { 59: char aname[8]; 60: int atime[2]; 61: char auid, amode; 62: int asize; 63: } archdr; 64: 65: struct filhdr { 66: int fmagic; 67: int tsize; 68: int dsize; 69: int bsize; 70: int ssize; 71: int entry; 72: int pad; 73: int relflg; 74: } filhdr; 75: 76: struct liblist { 77: int off; 78: int bno; 79: }; 80: 81: struct liblist liblist[NROUT]; 82: struct liblist *libp { &liblist[0] }; 83: 84: struct symbol { 85: char sname[8]; 86: char stype; 87: char spad; 88: int svalue; 89: }; 90: 91: struct symbol cursym; 92: struct symbol symtab[NSYM]; 93: struct symbol *hshtab[NSYM+2]; 94: struct symbol *symp { symtab }; 95: struct symbol **local[NSYMPR]; 96: struct symbol *p_etext; 97: struct symbol *p_edata; 98: struct symbol *p_end; 99: 100: int xflag; /* discard local symbols */ 101: int Xflag; /* discard locals starting with 'L' */ 102: int rflag; /* preserve relocation bits, don't define common */ 103: int arflag; /* original copy of rflag */ 104: int sflag; /* discard all symbols */ 105: int nflag; /* pure procedure */ 106: int dflag; /* define common even with rflag */ 107: int iflag; /* I/D space separated */ 108: 109: int infil; 110: char *filname; 111: 112: int tsize; 113: int dsize; 114: int bsize; 115: int ssize; 116: int nsym; 117: 118: int torigin; 119: int dorigin; 120: int borigin; 121: 122: int ctrel; 123: int cdrel; 124: int cbrel; 125: 126: int errlev; 127: int delarg 4; 128: char tfname[] "/tmp/lxyyyyy"; 129: int toutb[259]; 130: int doutb[259]; 131: int troutb[259]; 132: int droutb[259]; 133: int soutb[259]; 134: 135: struct symbol **lookup(); 136: struct symbol **slookup(); 137: 138: main(argc, argv) 139: char **argv; 140: { 141: extern int delexit(); 142: register c; 143: register char *ap, **p; 144: struct symbol **hp; 145: 146: if ((signal(SIGINT, 1) & 01) == 0) 147: signal(SIGINT, delexit); 148: if (argc == 1) 149: exit(4); 150: p = argv + 1; 151: for (c = 1; c<argc; c++) { 152: filname = 0; 153: ap = *p++; 154: if (*ap == '-') switch (ap[1]) { 155: 156: case 'u': 157: if (++c >= argc) 158: error(1, "Bad 'use'"); 159: if (*(hp = slookup(*p++)) == 0) { 160: *hp = symp; 161: enter(); 162: } 163: continue; 164: 165: case 'l': 166: break; 167: 168: case 'x': 169: xflag++; 170: continue; 171: 172: case 'X': 173: Xflag++; 174: continue; 175: 176: case 'r': 177: rflag++; 178: arflag++; 179: continue; 180: 181: case 's': 182: sflag++; 183: xflag++; 184: continue; 185: 186: case 'n': 187: nflag++; 188: continue; 189: 190: case 'd': 191: dflag++; 192: continue; 193: 194: case 'i': 195: iflag++; 196: continue; 197: } 198: load1arg(ap); 199: close(infil); 200: } 201: middle(); 202: setupout(); 203: p = argv+1; 204: libp = liblist; 205: for (c=1; c<argc; c++) { 206: ap = *p++; 207: if (*ap == '-') switch (ap[1]) { 208: 209: case 'u': 210: ++c; 211: ++p; 212: default: 213: continue; 214: 215: case 'l': 216: break; 217: } 218: load2arg(ap); 219: close(infil); 220: } 221: finishout(); 222: } 223: 224: load1arg(acp) 225: char *acp; 226: { 227: register char *cp; 228: register noff, nbno; 229: 230: cp = acp; 231: if (getfile(cp)==0) { 232: load1(0, 0, 0); 233: return; 234: } 235: nbno = 0; 236: noff = 1; 237: for (;;) { 238: dseek(&text, nbno, noff, sizeof archdr); 239: if (text.size <= 0) { 240: libp->bno = -1; 241: libp++; 242: return; 243: } 244: mget(&archdr, sizeof archdr); 245: if (load1(1, nbno, noff + (sizeof archdr) / 2)) { 246: libp->bno = nbno; 247: libp->off = noff; 248: libp++; 249: } 250: noff =+ (archdr.asize + sizeof archdr)>>1; 251: nbno =+ (noff >> 8) & 0377; 252: noff =& 0377; 253: } 254: } 255: 256: load1(libflg, bno, off) 257: { 258: register struct symbol *sp, **hp, ***cp; 259: struct symbol *ssymp; 260: int ndef, nloc; 261: 262: readhdr(bno, off); 263: ctrel = tsize; 264: cdrel =+ dsize; 265: cbrel =+ bsize; 266: ndef = 0; 267: nloc = sizeof cursym; 268: cp = local; 269: ssymp = symp; 270: if ((filhdr.relflg&RELFLG)==1) { 271: error(0, "No relocation bits"); 272: return(0); 273: } 274: off =+ (sizeof filhdr)/2 + filhdr.tsize + filhdr.dsize; 275: dseek(&text, bno, off, filhdr.ssize); 276: while (text.size > 0) { 277: mget(&cursym, sizeof cursym); 278: if ((cursym.stype&EXTERN)==0) { 279: if (Xflag==0 || cursym.sname[0]!='L') 280: nloc =+ sizeof cursym; 281: continue; 282: } 283: symreloc(); 284: hp = lookup(); 285: if ((sp = *hp) == 0) { 286: *hp = enter(); 287: *cp++ = hp; 288: continue; 289: } 290: if (sp->stype != EXTERN+UNDEF) 291: continue; 292: if (cursym.stype == EXTERN+UNDEF) { 293: if (cursym.svalue > sp->svalue) 294: sp->svalue = cursym.svalue; 295: continue; 296: } 297: if (sp->svalue != 0 && cursym.stype == EXTERN+TEXT) 298: continue; 299: ndef++; 300: sp->stype = cursym.stype; 301: sp->svalue = cursym.svalue; 302: } 303: if (libflg==0 || ndef) { 304: tsize =+ filhdr.tsize; 305: dsize =+ filhdr.dsize; 306: bsize =+ filhdr.bsize; 307: ssize =+ nloc; 308: return(1); 309: } 310: /* 311: * No symbols defined by this library member. 312: * Rip out the hash table entries and reset the symbol table. 313: */ 314: symp = ssymp; 315: while (cp > local) 316: **--cp = 0; 317: return(0); 318: } 319: 320: middle() 321: { 322: register struct symbol *sp; 323: register t, csize; 324: int nund, corigin; 325: 326: p_etext = *slookup("_etext"); 327: p_edata = *slookup("_edata"); 328: p_end = *slookup("_end"); 329: /* 330: * If there are any undefined symbols, save the relocation bits. 331: */ 332: if (rflag==0) for (sp=symtab; sp<symp; sp++) 333: if (sp->stype==EXTERN+UNDEF && sp->svalue==0 334: && sp!=p_end && sp!=p_edata && sp!=p_etext) { 335: rflag++; 336: dflag = 0; 337: nflag = 0; 338: iflag = 0; 339: sflag = 0; 340: break; 341: } 342: /* 343: * Assign common locations. 344: */ 345: csize = 0; 346: if (dflag || rflag==0) { 347: for (sp=symtab; sp<symp; sp++) 348: if (sp->stype==EXTERN+UNDEF && (t=sp->svalue)!=0) { 349: t = (t+1) & ~01; 350: sp->svalue = csize; 351: sp->stype = EXTERN+COMM; 352: csize =+ t; 353: } 354: if (p_etext && p_etext->stype==EXTERN+UNDEF) { 355: p_etext->stype = EXTERN+TEXT; 356: p_etext->svalue = tsize; 357: } 358: if (p_edata && p_edata->stype==EXTERN+UNDEF) { 359: p_edata->stype = EXTERN+DATA; 360: p_edata->svalue = dsize; 361: } 362: if (p_end && p_end->stype==EXTERN+UNDEF) { 363: p_end->stype = EXTERN+BSS; 364: p_end->svalue = bsize; 365: } 366: } 367: /* 368: * Now set symbols to their final value 369: */ 370: if (nflag || iflag) 371: tsize = (tsize + 077) & ~077; 372: dorigin = tsize; 373: if (nflag) 374: dorigin = (tsize+017777) & ~017777; 375: if (iflag) 376: dorigin = 0; 377: corigin = dorigin + dsize; 378: borigin = corigin + csize; 379: nund = 0; 380: for (sp=symtab; sp<symp; sp++) switch (sp->stype) { 381: case EXTERN+UNDEF: 382: errlev =| 01; 383: if (arflag==0 && sp->svalue==0) { 384: if (nund==0) 385: printf("Undefined:\n"); 386: nund++; 387: printf("%.8s\n", sp->sname); 388: } 389: continue; 390: 391: case EXTERN+ABS: 392: default: 393: continue; 394: 395: case EXTERN+TEXT: 396: sp->svalue =+ torigin; 397: continue; 398: 399: case EXTERN+DATA: 400: sp->svalue =+ dorigin; 401: continue; 402: 403: case EXTERN+BSS: 404: sp->svalue =+ borigin; 405: continue; 406: 407: case EXTERN+COMM: 408: sp->stype = EXTERN+BSS; 409: sp->svalue =+ corigin; 410: continue; 411: } 412: if (sflag || xflag) 413: ssize = 0; 414: bsize =+ csize; 415: nsym = ssize / (sizeof cursym); 416: } 417: 418: setupout() 419: { 420: register char *p; 421: register pid; 422: 423: if ((toutb[0] = creat("l.out", 0666)) < 0) 424: error(1, "Can't create l.out"); 425: pid = getpid(); 426: for (p = &tfname[12]; p > &tfname[7];) { 427: *--p = (pid&07) + '0'; 428: pid =>> 3; 429: } 430: tcreat(doutb, 'a'); 431: if (sflag==0 || xflag==0) 432: tcreat(soutb, 'b'); 433: if (rflag) { 434: tcreat(troutb, 'c'); 435: tcreat(droutb, 'd'); 436: } 437: filhdr.fmagic = FMAGIC; 438: if (nflag) 439: filhdr.fmagic = NMAGIC; 440: if (iflag) 441: filhdr.fmagic = IMAGIC; 442: filhdr.tsize = tsize; 443: filhdr.dsize = dsize; 444: filhdr.bsize = bsize; 445: filhdr.ssize = sflag? 0: (ssize + (sizeof cursym)*(symp-symtab)); 446: filhdr.entry = 0; 447: filhdr.pad = 0; 448: filhdr.relflg = (rflag==0); 449: mput(toutb, &filhdr, sizeof filhdr); 450: return; 451: } 452: 453: tcreat(buf, letter) 454: int *buf; 455: { 456: tfname[6] = letter; 457: if ((buf[0] = creat(tfname, RONLY)) < 0) 458: error(1, "Can't create temp"); 459: } 460: 461: load2arg(acp) 462: char *acp; 463: { 464: register char *cp; 465: register struct liblist *lp; 466: 467: cp = acp; 468: if (getfile(cp) == 0) { 469: while (*cp) 470: cp++; 471: while (cp >= acp && *--cp != '/'); 472: mkfsym(++cp); 473: load2(0, 0); 474: return; 475: } 476: for (lp = libp; lp->bno != -1; lp++) { 477: dseek(&text, lp->bno, lp->off, sizeof archdr); 478: mget(&archdr, sizeof archdr); 479: mkfsym(archdr.aname); 480: load2(lp->bno, lp->off + (sizeof archdr) / 2); 481: } 482: libp = ++lp; 483: } 484: 485: load2(bno, off) 486: { 487: register struct symbol *sp; 488: register int *lp, symno; 489: 490: readhdr(bno, off); 491: ctrel = torigin; 492: cdrel =+ dorigin; 493: cbrel =+ borigin; 494: /* 495: * Reread the symbol table, recording the numbering 496: * of symbols for fixing external references. 497: */ 498: lp = local; 499: symno = -1; 500: off =+ (sizeof filhdr)/2; 501: dseek(&text, bno, off+filhdr.tsize+filhdr.dsize, filhdr.ssize); 502: while (text.size > 0) { 503: symno++; 504: mget(&cursym, sizeof cursym); 505: symreloc(); 506: if ((cursym.stype&EXTERN) == 0) { 507: if (!sflag&&!xflag&&(!Xflag||cursym.sname[0]!='L')) 508: mput(soutb, &cursym, sizeof cursym); 509: continue; 510: } 511: if ((sp = *lookup()) == 0) 512: error(1, "internal error: symbol not found"); 513: if (cursym.stype == EXTERN+UNDEF) { 514: if (lp >= &local[NSYMPR]) 515: error(1, "Local symbol overflow"); 516: *lp++ = symno; 517: *lp++ = sp; 518: continue; 519: } 520: if (cursym.stype!=sp->stype || cursym.svalue!=sp->svalue) { 521: printf("%.8s: ", cursym.sname); 522: error(0, "Multiply defined"); 523: } 524: } 525: dseek(&text, bno, off, filhdr.tsize); 526: dseek(&reloc, bno, off+(filhdr.tsize+filhdr.dsize)/2, filhdr.tsize); 527: load2td(lp, ctrel, toutb, troutb); 528: dseek(&text, bno, off+(filhdr.tsize/2), filhdr.dsize); 529: dseek(&reloc, bno, off+filhdr.tsize+(filhdr.dsize/2), filhdr.dsize); 530: load2td(lp, cdrel, doutb, droutb); 531: torigin =+ filhdr.tsize; 532: dorigin =+ filhdr.dsize; 533: borigin =+ filhdr.bsize; 534: } 535: 536: load2td(lp, creloc, b1, b2) 537: int *lp; 538: { 539: register r, t; 540: register struct symbol *sp; 541: 542: for (;;) { 543: /* 544: * The pickup code is copied from "get" for speed. 545: */ 546: if (--text.size <= 0) { 547: if (text.size < 0) 548: break; 549: text.size++; 550: t = get(&text); 551: } else if (--text.nibuf < 0) { 552: text.nibuf++; 553: text.size++; 554: t = get(&text); 555: } else 556: t = *text.ptr++; 557: if (--reloc.size <= 0) { 558: if (reloc.size < 0) 559: error(1, "Relocation error"); 560: reloc.size++; 561: r = get(&reloc); 562: } else if (--reloc.nibuf < 0) { 563: reloc.nibuf++; 564: reloc.size++; 565: r = get(&reloc); 566: } else 567: r = *reloc.ptr++; 568: switch (r&016) { 569: 570: case RTEXT: 571: t =+ ctrel; 572: break; 573: 574: case RDATA: 575: t =+ cdrel; 576: break; 577: 578: case RBSS: 579: t =+ cbrel; 580: break; 581: 582: case REXT: 583: sp = lookloc(lp, r); 584: if (sp->stype==EXTERN+UNDEF) { 585: r = (r&01) + ((nsym+(sp-symtab))<<4) + REXT; 586: break; 587: } 588: t =+ sp->svalue; 589: r = (r&01) + ((sp->stype-(EXTERN+ABS))<<1); 590: break; 591: } 592: if (r&01) 593: t =- creloc; 594: putw(t, b1); 595: if (rflag) 596: putw(r, b2); 597: } 598: } 599: 600: finishout() 601: { 602: register n, *p; 603: 604: if (nflag||iflag) { 605: n = torigin; 606: while (n&077) { 607: n =+ 2; 608: putw(0, toutb); 609: if (rflag) 610: putw(0, troutb); 611: } 612: } 613: copy(doutb, 'a'); 614: if (rflag) { 615: copy(troutb, 'c'); 616: copy(droutb, 'd'); 617: } 618: if (sflag==0) { 619: if (xflag==0) 620: copy(soutb, 'b'); 621: for (p=symtab; p < symp;) 622: putw(*p++, toutb); 623: } 624: fflush(toutb); 625: close(toutb[0]); 626: unlink("a.out"); 627: link("l.out", "a.out"); 628: delarg = errlev; 629: delexit(); 630: } 631: 632: delexit() 633: { 634: register c; 635: 636: unlink("l.out"); 637: for (c = 'a'; c <= 'd'; c++) { 638: tfname[6] = c; 639: unlink(tfname); 640: } 641: if (delarg==0) 642: chmod("a.out", 0777); 643: exit(delarg); 644: } 645: 646: copy(buf, c) 647: int *buf; 648: { 649: register f, *p, n; 650: 651: fflush(buf); 652: close(buf[0]); 653: tfname[6] = c; 654: f = open(tfname, 0); 655: while ((n = read(f, doutb, 512)) > 1) { 656: n =>> 1; 657: p = doutb; 658: do 659: putw(*p++, toutb); 660: while (--n); 661: } 662: close(f); 663: } 664: 665: mkfsym(s) 666: char *s; 667: { 668: 669: if (sflag || xflag) 670: return; 671: cp8c(s, cursym.sname); 672: cursym.stype = 037; 673: cursym.svalue = torigin; 674: mput(soutb, &cursym, sizeof cursym); 675: } 676: 677: mget(aloc, an) 678: int *aloc; 679: { 680: register *loc, n; 681: register *p; 682: 683: n = an; 684: n =>> 1; 685: loc = aloc; 686: if ((text.nibuf =- n) >= 0) { 687: if ((text.size =- n) > 0) { 688: p = text.ptr; 689: do 690: *loc++ = *p++; 691: while (--n); 692: text.ptr = p; 693: return; 694: } else 695: text.size =+ n; 696: } 697: text.nibuf =+ n; 698: do { 699: *loc++ = get(&text); 700: } while (--n); 701: } 702: 703: mput(buf, aloc, an) 704: int *aloc; 705: { 706: register *loc; 707: register n; 708: 709: loc = aloc; 710: n = an>>1; 711: do { 712: putw(*loc++, buf); 713: } while (--n); 714: } 715: 716: dseek(asp, ab, o, s) 717: { 718: register struct stream *sp; 719: register struct page *p; 720: register b; 721: int n; 722: 723: sp = asp; 724: b = ab + ((o>>8) & 0377); 725: o =& 0377; 726: --sp->pno->nuser; 727: if ((p = &page[0])->bno!=b && (p = &page[1])->bno!=b) 728: if (p->nuser==0 || (p = &page[0])->nuser==0) { 729: if (page[0].nuser==0 && page[1].nuser==0) 730: if (page[0].bno < page[1].bno) 731: p = &page[0]; 732: p->bno = b; 733: seek(infil, b, 3); 734: if ((n = read(infil, p->buff, 512)>>1) < 0) 735: n = 0; 736: p->nibuf = n; 737: } else 738: error(1, "No pages"); 739: ++p->nuser; 740: sp->bno = b; 741: sp->pno = p; 742: sp->ptr = p->buff + o; 743: if (s != -1) 744: sp->size = (s>>1) & 077777; 745: if ((sp->nibuf = p->nibuf-o) <= 0) 746: sp->size = 0; 747: } 748: 749: get(asp) 750: struct stream *asp; 751: { 752: register struct stream *sp; 753: 754: sp = asp; 755: if (--sp->nibuf < 0) { 756: dseek(sp, sp->bno+1, 0, -1); 757: --sp->nibuf; 758: } 759: if (--sp->size <= 0) { 760: if (sp->size < 0) 761: error(1, premeof); 762: ++fpage.nuser; 763: --sp->pno->nuser; 764: sp->pno = &fpage; 765: } 766: return(*sp->ptr++); 767: } 768: 769: getfile(acp) 770: char *acp; 771: { 772: register char *cp; 773: register c; 774: 775: cp = acp; 776: archdr.aname[0] = '\0'; 777: if (cp[0]=='-' && cp[1]=='l') { 778: if ((c = cp[2]) == '\0') 779: c = 'a'; 780: cp = "/lib/lib?.a"; 781: cp[8] = c; 782: } 783: filname = cp; 784: if ((infil = open(cp, 0)) < 0) 785: error(1, "cannot open"); 786: page[0].bno = page[1].bno = -1; 787: page[0].nuser = page[1].nuser = 0; 788: text.pno = reloc.pno = &fpage; 789: fpage.nuser = 2; 790: dseek(&text, 0, 0, 2); 791: if (text.size <= 0) 792: error(1, premeof); 793: return(get(&text) == ARCMAGIC); 794: } 795: 796: struct symbol **lookup() 797: { 798: int i; 799: register struct symbol **hp; 800: register char *cp, *cp1; 801: 802: i = 0; 803: for (cp=cursym.sname; cp < &cursym.sname[8];) 804: i = (i<<1) + *cp++; 805: for (hp = &hshtab[(i&077777)%NSYM+2]; *hp!=0;) { 806: cp1 = (*hp)->sname; 807: for (cp=cursym.sname; cp < &cursym.sname[8];) 808: if (*cp++ != *cp1++) 809: goto no; 810: break; 811: no: 812: if (++hp >= &hshtab[NSYM+2]) 813: hp = hshtab; 814: } 815: return(hp); 816: } 817: 818: struct symbol **slookup(s) 819: char *s; 820: { 821: cp8c(s, cursym.sname); 822: cursym.stype = EXTERN+UNDEF; 823: cursym.svalue = 0; 824: return(lookup()); 825: } 826: 827: enter() 828: { 829: register struct symbol *sp; 830: 831: if ((sp=symp) >= &symtab[NSYM]) 832: error(1, "Symbol table overflow"); 833: cp8c(cursym.sname, sp->sname); 834: sp->stype = cursym.stype; 835: sp->svalue = cursym.svalue; 836: symp++; 837: return(sp); 838: } 839: 840: symreloc() 841: { 842: switch (cursym.stype) { 843: 844: case TEXT: 845: case EXTERN+TEXT: 846: cursym.svalue =+ ctrel; 847: return; 848: 849: case DATA: 850: case EXTERN+DATA: 851: cursym.svalue =+ cdrel; 852: return; 853: 854: case BSS: 855: case EXTERN+BSS: 856: cursym.svalue =+ cbrel; 857: return; 858: 859: case EXTERN+UNDEF: 860: return; 861: } 862: if (cursym.stype&EXTERN) 863: cursym.stype = EXTERN+ABS; 864: } 865: 866: error(n, s) 867: char *s; 868: { 869: if (filname) { 870: printf("%s", filname); 871: if (archdr.aname[0]) 872: printf("(%.8s)", archdr.aname); 873: printf(": "); 874: } 875: printf("%s\n", s); 876: if (n) 877: delexit(); 878: errlev = 2; 879: } 880: 881: lookloc(alp, r) 882: { 883: register int *clp, *lp; 884: register sn; 885: 886: lp = alp; 887: sn = (r>>4) & 07777; 888: for (clp=local; clp<lp; clp =+ 2) 889: if (clp[0] == sn) 890: return(clp[1]); 891: error(1, "Local symbol botch"); 892: } 893: 894: readhdr(bno, off) 895: { 896: register st, sd; 897: 898: dseek(&text, bno, off, sizeof filhdr); 899: mget(&filhdr, sizeof filhdr); 900: if (filhdr.fmagic != FMAGIC) 901: error(1, "Bad format"); 902: st = (filhdr.tsize+01) & ~01; 903: filhdr.tsize = st; 904: cdrel = -st; 905: sd = (filhdr.dsize+01) & ~01; 906: cbrel = - (st+sd); 907: filhdr.bsize = (filhdr.bsize+01) & ~01; 908: } 909: 910: cp8c(from, to) 911: char *from, *to; 912: { 913: register char *f, *t, *te; 914: 915: f = from; 916: t = to; 917: te = t+8; 918: while ((*t++ = *f++) && t<te); 919: while (t<te) 920: *t++ = 0; 921: }