new copyright notice
[unix-history] / usr / src / old / ld / ld.c
index c06b5e3..10b643f 100644 (file)
@@ -1,17 +1,34 @@
-static char sccsid[] = "@(#)ld.c 3.1 %G%";
 /*
 /*
- * VAX VM/UNIX ld - string table version
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
  */
 
  */
 
-#include <sys/types.h>
-#include <signal.h>
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1980 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif not lint
+
+#ifndef lint
+static char sccsid[] = "@(#)ld.c       5.14 (Berkeley) %G%";
+#endif not lint
+
+/*
+ * ld - string table version for VAX
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/signal.h>
+#include <ar.h>
+#include <a.out.h>
+#include <ranlib.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <ctype.h>
-#include <newar.h>
-#include <newa.out.h>
-#include <ranlib.h>
-#include <stat.h>
-#include <pagsiz.h>
+#include <string.h>
+#include "pathnames.h"
 
 /*
  * Basic strategy:
 
 /*
  * Basic strategy:
@@ -107,7 +124,7 @@ int nsym;                   /* pass2: number of local symbols in a.out */
 /* nsym + symx(nextsym) is the symbol table size during pass2 */
 
 struct nlist **lookup(), **slookup();
 /* nsym + symx(nextsym) is the symbol table size during pass2 */
 
 struct nlist **lookup(), **slookup();
-struct nlist *p_data, *p_etext, *p_edata, *p_end, *entrypt;
+struct nlist *p_etext, *p_edata, *p_end, *entrypt;
 
 /*
  * Definitions of segmentation for library member table.
 
 /*
  * Definitions of segmentation for library member table.
@@ -134,8 +151,6 @@ struct      libseg {
  * which maps these internal numbers to symbol table entries.
  * A hash table is constructed, based on the local symbol table indices,
  * for quick lookup of these symbols.
  * which maps these internal numbers to symbol table entries.
  * A hash table is constructed, based on the local symbol table indices,
  * for quick lookup of these symbols.
- *
- * COULD JUST KEEP WHOLE SYMBOL TABLE AROUND.
  */
 #define        LHSIZ   31
 struct local {
  */
 #define        LHSIZ   31
 struct local {
@@ -171,17 +186,24 @@ char      *tabstr;        /* string table for table of contents */
  * We open each input file or library only once, but in pass2 we
  * (historically) read from such a file at 2 different places at the
  * same time.  These structures are remnants from those days,
  * We open each input file or library only once, but in pass2 we
  * (historically) read from such a file at 2 different places at the
  * same time.  These structures are remnants from those days,
- * and now serve only to catch ``Premature EOF''... soon to be gone...
+ * and now serve only to catch ``Premature EOF''.
+ * In order to make I/O more efficient, we provide routines which
+ * use the optimal block size returned by stat().
  */
  */
+#define BLKSIZE 1024
 typedef struct {
        short   *fakeptr;
        int     bno;
        int     nibuf;
        int     nuser;
 typedef struct {
        short   *fakeptr;
        int     bno;
        int     nibuf;
        int     nuser;
-       char    buff[BSIZE];
+       char    *buff;
+       int     bufsize;
 } PAGE;
 
 PAGE   page[2];
 } PAGE;
 
 PAGE   page[2];
+int    p_blksize;
+int    p_blkshift;
+int    p_blkmask;
 
 struct {
        short   *fakeptr;
 
 struct {
        short   *fakeptr;
@@ -219,12 +241,16 @@ int       Sflag;          /* discard all except locals and globals*/
 int    rflag;          /* preserve relocation bits, don't define common */
 int    arflag;         /* original copy of rflag */
 int    sflag;          /* discard all symbols */
 int    rflag;          /* preserve relocation bits, don't define common */
 int    arflag;         /* original copy of rflag */
 int    sflag;          /* discard all symbols */
+int    Mflag;          /* print rudimentary load map */
 int    nflag;          /* pure procedure */
 int    dflag;          /* define common even with rflag */
 int    nflag;          /* pure procedure */
 int    dflag;          /* define common even with rflag */
-int    zflag = 1;      /* demand paged  */
+int    zflag;          /* demand paged  */
 long   hsize;          /* size of hole at beginning of data to be squashed */
 int    Aflag;          /* doing incremental load */
 long   hsize;          /* size of hole at beginning of data to be squashed */
 int    Aflag;          /* doing incremental load */
+int    Nflag;          /* want impure a.out */
 int    funding;        /* reading fundamental file for incremental load */
 int    funding;        /* reading fundamental file for incremental load */
+int    yflag;          /* number of symbols to be traced */
+char   **ytab;         /* the symbols */
 
 /*
  * These are the cumulative sizes, set in pass 1, which
 
 /*
  * These are the cumulative sizes, set in pass 1, which
@@ -236,16 +262,22 @@ off_t     tsize, dsize, bsize, trsize, drsize, ssize;
  * Symbol relocation: c?rel is a scale factor which is
  * added to an old relocation to convert it to new units;
  * i.e. it is the difference between segment origins.
  * Symbol relocation: c?rel is a scale factor which is
  * added to an old relocation to convert it to new units;
  * i.e. it is the difference between segment origins.
+ * (Thus if we are loading from a data segment which began at location
+ * 4 in a .o file into an a.out where it will be loaded starting at
+ * 1024, cdrel will be 1020.)
  */
 long   ctrel, cdrel, cbrel;
 
 /*
  */
 long   ctrel, cdrel, cbrel;
 
 /*
- * Textbase is the starting text address, 0 unless given by -H.
+ * Textbase is the start address of all text, 0 unless given by -T.
  * Database is the base of all data, computed before and used during pass2.
  * Database is the base of all data, computed before and used during pass2.
+ */
+long   textbase, database;
+
+/*
  * The base addresses for the loaded text, data and bss from the
  * current module during pass2 are given by torigin, dorigin and borigin.
  */
  * The base addresses for the loaded text, data and bss from the
  * current module during pass2 are given by torigin, dorigin and borigin.
  */
-long   textbase, database;
 long   torigin, dorigin, borigin;
 
 /*
 long   torigin, dorigin, borigin;
 
 /*
@@ -268,9 +300,10 @@ int        delarg  = 4;
  */
 struct biobuf {
        short   b_nleft;                /* Number free spaces left in b_buf */
  */
 struct biobuf {
        short   b_nleft;                /* Number free spaces left in b_buf */
-/* Initialize to be less than BUFSIZ initially, to boundary align in file */
+/* Initialize to be less than b_bufsize initially, to boundary align in file */
        char    *b_ptr;                 /* Next place to stuff characters */
        char    *b_ptr;                 /* Next place to stuff characters */
-       char    b_buf[BUFSIZ];          /* The buffer itself */
+       char    *b_buf;                 /* Pointer to the buffer */
+       int     b_bufsize;              /* Size of the buffer */
        off_t   b_off;                  /* Current file offset */
        struct  biobuf *b_link;         /* Link in chain for bflush() */
 } *biobufs;
        off_t   b_off;                  /* Current file offset */
        struct  biobuf *b_link;         /* Link in chain for bflush() */
 } *biobufs;
@@ -289,18 +322,31 @@ struct    biobuf *tout, *dout, *trout, *drout, *sout, *strout;
 off_t  offset = sizeof (off_t);
 
 int    ofilfnd;                /* -o given; otherwise move l.out to a.out */
 off_t  offset = sizeof (off_t);
 
 int    ofilfnd;                /* -o given; otherwise move l.out to a.out */
-char   *ofilename = "l.out";
+char   *defaultname;           /* l.out */
+char   *ofilename;             /* name given to -o */
+int    ofilemode;              /* respect umask even for unsucessful ld's */
 int    infil;                  /* current input file descriptor */
 char   *filname;               /* and its name */
 
 int    infil;                  /* current input file descriptor */
 char   *filname;               /* and its name */
 
+#define        NDIRS   25
+#define NDEFDIRS 3             /* number of default directories in dirs[] */
+char   *dirs[NDIRS];           /* directories for library search */
+int    ndir;                   /* number of directories */
+
 /*
  * Base of the string table of the current module (pass1 and pass2).
  */
 char   *curstr;
 
 /*
  * Base of the string table of the current module (pass1 and pass2).
  */
 char   *curstr;
 
+/*
+ * System software page size, as returned by getpagesize.
+ */
+int    pagesize;
+
 char   get();
 int    delexit();
 char   *savestr();
 char   get();
 int    delexit();
 char   *savestr();
+char   *malloc();
 
 main(argc, argv)
 char **argv;
 
 main(argc, argv)
 char **argv;
@@ -310,13 +356,36 @@ char **argv;
        register char *ap, **p;
        char save;
 
        register char *ap, **p;
        char save;
 
-       if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+       if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
                signal(SIGINT, delexit);
                signal(SIGINT, delexit);
+               signal(SIGTERM, delexit);
+       }
        if (argc == 1)
                exit(4);
        if (argc == 1)
                exit(4);
-       p = argv+1;
+       ofilename = defaultname = (char *)genbuildname("l.out");
+       pagesize = getpagesize();
+
+       /* 
+        * Pull out search directories.
+        */
+       for (c = 1; c < argc; c++) {
+               ap = argv[c];
+               if (ap[0] == '-' && ap[1] == 'L') {
+                       if (ap[2] == 0)
+                               error(1, "-L: pathname missing");
+                       if (ndir >= NDIRS - NDEFDIRS)
+                               error(1, "-L: too many directories");
+                       dirs[ndir++] = &ap[2];
+               }
+       }
+       /* add default search directories */
+       dirs[ndir++] = _PATH_USRLIB;
+       dirs[ndir++] = _PATH_LOCALLIB;
 
 
-       /* scan files once to find symdefs */
+       p = argv+1;
+       /*
+        * Scan files once to find where symbols are defined.
+        */
        for (c=1; c<argc; c++) {
                if (trace)
                        printf("%s:\n", *p);
        for (c=1; c<argc; c++) {
                if (trace)
                        printf("%s:\n", *p);
@@ -331,13 +400,13 @@ char **argv;
                case 'o':
                        if (++c >= argc)
                                error(1, "-o where?");
                case 'o':
                        if (++c >= argc)
                                error(1, "-o where?");
-                       ofilename = *p++;
+                       ofilename = (char *)genbuildname(*p++);
                        ofilfnd++;
                        continue;
                case 'u':
                case 'e':
                        if (++c >= argc)
                        ofilfnd++;
                        continue;
                case 'u':
                case 'e':
                        if (++c >= argc)
-                               error(1, "-u or -c: arg missing");
+                               error(1, " -u or -e: arg missing");
                        enter(slookup(*p++));
                        if (ap[i]=='e')
                                entrypt = lastsym;
                        enter(slookup(*p++));
                        if (ap[i]=='e')
                                entrypt = lastsym;
@@ -384,6 +453,9 @@ char **argv;
                        load1arg(&ap[i]); 
                        ap[i]=save;
                        goto next;
                        load1arg(&ap[i]); 
                        ap[i]=save;
                        goto next;
+               case 'M':
+                       Mflag++;
+                       continue;
                case 'x':
                        xflag++;
                        continue;
                case 'x':
                        xflag++;
                        continue;
@@ -396,8 +468,6 @@ char **argv;
                case 'r':
                        rflag++;
                        arflag++;
                case 'r':
                        rflag++;
                        arflag++;
-                       zflag = 0;
-                       nflag = 1;
                        continue;
                case 's':
                        sflag++;
                        continue;
                case 's':
                        sflag++;
@@ -405,11 +475,11 @@ char **argv;
                        continue;
                case 'n':
                        nflag++;
                        continue;
                case 'n':
                        nflag++;
-                       zflag = 0;
+                       Nflag = zflag = 0;
                        continue;
                case 'N':
                        continue;
                case 'N':
-                       nflag = 0;
-                       zflag = 0;
+                       Nflag++;
+                       nflag = zflag = 0;
                        continue;
                case 'd':
                        dflag++;
                        continue;
                case 'd':
                        dflag++;
@@ -420,10 +490,22 @@ char **argv;
                case 't':
                        trace++;
                        continue;
                case 't':
                        trace++;
                        continue;
+               case 'y':
+                       if (ap[i+1] == 0)
+                               error(1, "-y: symbol name missing");
+                       if (yflag == 0) {
+                               ytab = (char **)calloc(argc, sizeof (char **));
+                               if (ytab == 0)
+                                       error(1, "ran out of memory (-y)");
+                       }
+                       ytab[yflag++] = &ap[i+1];
+                       goto next;
                case 'z':
                        zflag++;
                case 'z':
                        zflag++;
-                       nflag = 0;
+                       Nflag = nflag = 0;
                        continue;
                        continue;
+               case 'L':
+                       goto next;
                default:
                        filname = savestr("-x");        /* kludge */
                        filname[1] = ap[i];             /* kludge */
                default:
                        filname = savestr("-x");        /* kludge */
                        filname[1] = ap[i];             /* kludge */
@@ -433,6 +515,8 @@ char **argv;
 next:
                ;
        }
 next:
                ;
        }
+       if (rflag == 0 && Nflag == 0 && nflag == 0)
+               zflag++;
        endload(argc, argv);
        exit(0);
 }
        endload(argc, argv);
        exit(0);
 }
@@ -463,11 +547,29 @@ htoi(p)
 
 delexit()
 {
 
 delexit()
 {
+       struct stat stbuf;
+       long size;
+       char c = 0;
 
        bflush();
 
        bflush();
-       unlink("l.out");
+       unlink(defaultname);
+       /*
+        * We have to insure that the last block of the data segment
+        * is allocated a full pagesize block. If the underlying
+        * file system allocates frags that are smaller than pagesize,
+        * a full zero filled pagesize block needs to be allocated so 
+        * that when it is demand paged, the paged in block will be 
+        * appropriately filled with zeros.
+        */
+       fstat(biofd, &stbuf);
+       size = round(stbuf.st_size, pagesize);
+       if (!rflag && size > stbuf.st_size) {
+               lseek(biofd, size - 1, 0);
+               if (write(biofd, &c, 1) != 1)
+                       delarg |= 4;
+       }
        if (delarg==0 && Aflag==0)
        if (delarg==0 && Aflag==0)
-               chmod(ofilename, 0777 &~ umask(0));
+               (void) chmod(ofilename, ofilemode);
        exit (delarg);
 }
 
        exit (delarg);
 }
 
@@ -516,6 +618,9 @@ endload(argc, argv)
                        funding = 0;
                        c++;
                        continue;
                        funding = 0;
                        c++;
                        continue;
+               case 'y':
+               case 'L':
+                       goto next;
                case 'l':
                        ap[--i]='-'; 
                        load2arg(&ap[i]);
                case 'l':
                        ap[--i]='-'; 
                        load2arg(&ap[i]);
@@ -535,8 +640,12 @@ load1arg(cp)
 {
        register struct ranlib *tp;
        off_t nloc;
 {
        register struct ranlib *tp;
        off_t nloc;
+       int kind;
 
 
-       switch (getfile(cp)) {
+       kind = getfile(cp);
+       if (Mflag)
+               printf("%s\n", filname);
+       switch (kind) {
 
        /*
         * Plain file.
 
        /*
         * Plain file.
@@ -550,7 +659,8 @@ load1arg(cp)
         * (Slowly) process each member.
         */
        case 1:
         * (Slowly) process each member.
         */
        case 1:
-               error(-1, "warning: archive has no table of contents");
+               error(-1,
+"warning: archive has no table of contents; add one using ranlib(1)");
                nloc = SARMAG;
                while (step(nloc))
                        nloc += sizeof(archdr) +
                nloc = SARMAG;
                while (step(nloc))
                        nloc += sizeof(archdr) +
@@ -592,8 +702,8 @@ load1arg(cp)
                }
                while (ldrand())
                        continue;
                }
                while (ldrand())
                        continue;
-               cfree((char *)tab);
-               cfree(tabstr);
+               free((char *)tab);
+               free(tabstr);
                nextlibp(-1);
                break;
 
                nextlibp(-1);
                break;
 
@@ -602,7 +712,8 @@ load1arg(cp)
         * as a normal library (but skip the __.SYMDEF file).
         */
        case 3:
         * as a normal library (but skip the __.SYMDEF file).
         */
        case 3:
-               error(-1, "warning: table of contents is out of date");
+               error(-1,
+"warning: table of contents for archive is out of date; rerun ranlib(1)");
                nloc = SARMAG;
                do
                        nloc += sizeof(archdr) +
                nloc = SARMAG;
                do
                        nloc += sizeof(archdr) +
@@ -651,6 +762,8 @@ nextlibp(val)
                        error(1, "ran out of memory (nextlibp)");
        }
        clibseg->li_first[clibseg->li_used++] = val;
                        error(1, "ran out of memory (nextlibp)");
        }
        clibseg->li_first[clibseg->li_used++] = val;
+       if (val != -1 && Mflag)
+               printf("\t%s\n", archdr.ar_name);
 }
 
 /*
 }
 
 /*
@@ -669,7 +782,7 @@ ldrand()
 
        tplast = &tab[tnum-1];
        for (tp = tab; tp <= tplast; tp++) {
 
        tplast = &tab[tnum-1];
        for (tp = tab; tp <= tplast; tp++) {
-               if ((hp = slookup(tp->ran_un.ran_name)) == 0)
+               if ((hp = slookup(tp->ran_un.ran_name)) == 0 || *hp == 0)
                        continue;
                sp = *hp;
                if (sp->n_type != N_EXT+N_UNDF)
                        continue;
                sp = *hp;
                if (sp->n_type != N_EXT+N_UNDF)
@@ -697,8 +810,12 @@ load1(libflg, loc)
 
        readhdr(loc);
        if (filhdr.a_syms == 0) {
 
        readhdr(loc);
        if (filhdr.a_syms == 0) {
-               if (filhdr.a_text+filhdr.a_data == 0)
+               if (filhdr.a_text+filhdr.a_data == 0) {
+                       /* load2() adds a symbol for the file name */
+                       if (!libflg)
+                               ssize += sizeof (cursym);
                        return (0);
                        return (0);
+               }
                error(1, "no namelist");
        }
        if (libflg)
                error(1, "no namelist");
        }
        if (libflg)
@@ -792,7 +909,6 @@ middle()
        dorigin = 0; 
        borigin = 0;
 
        dorigin = 0; 
        borigin = 0;
 
-       p_data = *slookup("_data");
        p_etext = *slookup("_etext");
        p_edata = *slookup("_edata");
        p_end = *slookup("_end");
        p_etext = *slookup("_etext");
        p_edata = *slookup("_edata");
        p_end = *slookup("_end");
@@ -804,8 +920,7 @@ middle()
                for (i = 0; i < nsymt; i++) {
                        sp = xsym(i);
                        if (sp->n_type==N_EXT+N_UNDF && sp->n_value==0 &&
                for (i = 0; i < nsymt; i++) {
                        sp = xsym(i);
                        if (sp->n_type==N_EXT+N_UNDF && sp->n_value==0 &&
-                           sp!=p_end && sp!=p_edata &&
-                           sp!=p_etext && sp!=p_data) {
+                           sp!=p_end && sp!=p_edata && sp!=p_etext) {
                                rflag++;
                                dflag = 0;
                                break;
                                rflag++;
                                dflag = 0;
                                break;
@@ -821,10 +936,9 @@ middle()
        if (!Aflag)
                addsym = symseg[0].sy_first;
        database = round(tsize+textbase,
        if (!Aflag)
                addsym = symseg[0].sy_first;
        database = round(tsize+textbase,
-           (nflag||zflag? PAGSIZ : sizeof (long)));
+           (nflag||zflag? pagesize : sizeof (long)));
        database += hsize;
        if (dflag || rflag==0) {
        database += hsize;
        if (dflag || rflag==0) {
-               ldrsym(p_data, (long)0 , N_EXT+N_DATA);
                ldrsym(p_etext, tsize, N_EXT+N_TEXT);
                ldrsym(p_edata, dsize, N_EXT+N_DATA);
                ldrsym(p_end, bsize, N_EXT+N_BSS);
                ldrsym(p_etext, tsize, N_EXT+N_TEXT);
                ldrsym(p_edata, dsize, N_EXT+N_DATA);
                ldrsym(p_end, bsize, N_EXT+N_BSS);
@@ -865,8 +979,11 @@ middle()
                switch (sp->n_type & (N_TYPE+N_EXT)) {
 
                case N_EXT+N_UNDF:
                switch (sp->n_type & (N_TYPE+N_EXT)) {
 
                case N_EXT+N_UNDF:
-                       errlev |= 01;
+                       if (arflag == 0)
+                               errlev |= 01;
                        if ((arflag==0 || dflag) && sp->n_value==0) {
                        if ((arflag==0 || dflag) && sp->n_value==0) {
+                               if (sp==p_end || sp==p_etext || sp==p_edata)
+                                       continue;
                                if (nund==0)
                                        printf("Undefined:\n");
                                nund++;
                                if (nund==0)
                                        printf("Undefined:\n");
                                nund++;
@@ -896,7 +1013,6 @@ middle()
        bsize += csize;
        nsym = ssize / (sizeof cursym);
        if (Aflag) {
        bsize += csize;
        nsym = ssize / (sizeof cursym);
        if (Aflag) {
-               fixspec(p_data,dorigin);
                fixspec(p_etext,torigin);
                fixspec(p_edata,dorigin);
                fixspec(p_end,borigin);
                fixspec(p_etext,torigin);
                fixspec(p_edata,dorigin);
                fixspec(p_end,borigin);
@@ -933,17 +1049,26 @@ struct   biobuf toutb;
 
 setupout()
 {
 
 setupout()
 {
+       extern int errno;
        int bss;
        int bss;
-
-       biofd = creat(ofilename, 0666);
-       if (biofd < 0)
-               error(1, "cannot create output");
-       tout = &toutb;
-       bopen(tout, 0);
+       struct stat stbuf;
+
+       ofilemode = 0777 & ~umask(0);
+       biofd = creat(ofilename, 0666 & ofilemode);
+       if (biofd < 0) {
+               filname = ofilename;            /* kludge */
+               archdr.ar_name[0] = 0;          /* kludge */
+               error(1, strerror(errno));      /* kludge */
+       }
+       fstat(biofd, &stbuf);           /* suppose file exists, wrong*/
+       if (stbuf.st_mode & 0111) {     /* mode, ld fails? */
+               chmod(ofilename, stbuf.st_mode & 0666);
+               ofilemode = stbuf.st_mode;
+       }
        filhdr.a_magic = nflag ? NMAGIC : (zflag ? ZMAGIC : OMAGIC);
        filhdr.a_text = nflag ? tsize :
        filhdr.a_magic = nflag ? NMAGIC : (zflag ? ZMAGIC : OMAGIC);
        filhdr.a_text = nflag ? tsize :
-           round(tsize, zflag ? PAGSIZ : sizeof (long));
-       filhdr.a_data = zflag ? round(dsize, PAGSIZ) : dsize;
+           round(tsize, zflag ? pagesize : sizeof (long));
+       filhdr.a_data = zflag ? round(dsize, pagesize) : dsize;
        bss = bsize - (filhdr.a_data - dsize);
        if (bss < 0)
                bss = 0;
        bss = bsize - (filhdr.a_data - dsize);
        if (bss < 0)
                bss = 0;
@@ -960,33 +1085,32 @@ setupout()
                filhdr.a_entry = 0;
        filhdr.a_trsize = (rflag ? trsize:0);
        filhdr.a_drsize = (rflag ? drsize:0);
                filhdr.a_entry = 0;
        filhdr.a_trsize = (rflag ? trsize:0);
        filhdr.a_drsize = (rflag ? drsize:0);
+       tout = &toutb;
+       bopen(tout, 0, stbuf.st_blksize);
        bwrite((char *)&filhdr, sizeof (filhdr), tout);
        bwrite((char *)&filhdr, sizeof (filhdr), tout);
-       if (zflag) {
-               bflush1(tout);
-               biobufs = 0;
-               bopen(tout, PAGSIZ);
-       }
+       if (zflag)
+               bseek(tout, pagesize);
        wroff = N_TXTOFF(filhdr) + filhdr.a_text;
        wroff = N_TXTOFF(filhdr) + filhdr.a_text;
-       outb(&dout, filhdr.a_data);
+       outb(&dout, filhdr.a_data, stbuf.st_blksize);
        if (rflag) {
        if (rflag) {
-               outb(&trout, filhdr.a_trsize);
-               outb(&drout, filhdr.a_drsize);
+               outb(&trout, filhdr.a_trsize, stbuf.st_blksize);
+               outb(&drout, filhdr.a_drsize, stbuf.st_blksize);
        }
        if (sflag==0 || xflag==0) {
        }
        if (sflag==0 || xflag==0) {
-               outb(&sout, filhdr.a_syms);
+               outb(&sout, filhdr.a_syms, stbuf.st_blksize);
                wroff += sizeof (offset);
                wroff += sizeof (offset);
-               outb(&strout, 0);
+               outb(&strout, 0, stbuf.st_blksize);
        }
 }
 
        }
 }
 
-outb(bp, inc)
+outb(bp, inc, bufsize)
        register struct biobuf **bp;
 {
 
        *bp = (struct biobuf *)malloc(sizeof (struct biobuf));
        if (*bp == 0)
                error(1, "ran out of memory (outb)");
        register struct biobuf **bp;
 {
 
        *bp = (struct biobuf *)malloc(sizeof (struct biobuf));
        if (*bp == 0)
                error(1, "ran out of memory (outb)");
-       bopen(*bp, wroff);
+       bopen(*bp, wroff, bufsize);
        wroff += inc;
 }
 
        wroff += inc;
 }
 
@@ -1032,7 +1156,7 @@ long loc;
        int type;
 
        readhdr(loc);
        int type;
 
        readhdr(loc);
-       if(!funding) {
+       if (!funding) {
                ctrel = torigin;
                cdrel += dorigin;
                cbrel += borigin;
                ctrel = torigin;
                cdrel += dorigin;
                cbrel += borigin;
@@ -1091,6 +1215,14 @@ long loc;
                }
 /* end inline expansion of symreloc() */
                type = cursym.n_type;
                }
 /* end inline expansion of symreloc() */
                type = cursym.n_type;
+               if (yflag && cursym.n_un.n_name)
+                       for (i = 0; i < yflag; i++)
+                               /* fast check for 2d character! */
+                               if (ytab[i][1] == cursym.n_un.n_name[1] &&
+                                   !strcmp(ytab[i], cursym.n_un.n_name)) {
+                                       tracesym();
+                                       break;
+                               }
                if ((type&N_EXT) == 0) {
                        if (!sflag&&!xflag&&
                            (!Xflag||cursym.n_un.n_name[0]!='L'||type&N_STAB))
                if ((type&N_EXT) == 0) {
                        if (!sflag&&!xflag&&
                            (!Xflag||cursym.n_un.n_name[0]!='L'||type&N_STAB))
@@ -1131,30 +1263,148 @@ long loc;
                return;
        dseek(&text, loc, filhdr.a_text);
        dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize);
                return;
        dseek(&text, loc, filhdr.a_text);
        dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize);
-       load2td(ctrel, tout, trout);
+       load2td(ctrel, torigin - textbase, tout, trout);
        dseek(&text, loc+filhdr.a_text, filhdr.a_data);
        dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize,
            filhdr.a_drsize);
        dseek(&text, loc+filhdr.a_text, filhdr.a_data);
        dseek(&reloc, loc+filhdr.a_text+filhdr.a_data+filhdr.a_trsize,
            filhdr.a_drsize);
-       load2td(cdrel, dout, drout);
+       load2td(cdrel, dorigin - database, dout, drout);
        while (filhdr.a_data & (sizeof(long)-1)) {
                bputc(0, dout);
                filhdr.a_data++;
        }
        torigin += filhdr.a_text;
        while (filhdr.a_data & (sizeof(long)-1)) {
                bputc(0, dout);
                filhdr.a_data++;
        }
        torigin += filhdr.a_text;
-       dorigin += filhdr.a_data;
-       borigin += filhdr.a_bss;
+       dorigin += round(filhdr.a_data, sizeof (long));
+       borigin += round(filhdr.a_bss, sizeof (long));
        free(curstr);
 }
 
        free(curstr);
 }
 
-load2td(creloc, b1, b2)
-       long creloc;
+struct tynames {
+       int     ty_value;
+       char    *ty_name;
+} tynames[] = {
+       N_UNDF, "undefined",
+       N_ABS,  "absolute",
+       N_TEXT, "text",
+       N_DATA, "data",
+       N_BSS,  "bss",
+       N_COMM, "common",
+       0,      0,
+};
+
+tracesym()
+{
+       register struct tynames *tp;
+
+       if (cursym.n_type & N_STAB)
+               return;
+       printf("%s", filname);
+       if (archdr.ar_name[0])
+               printf("(%s)", archdr.ar_name);
+       printf(": ");
+       if ((cursym.n_type&N_TYPE) == N_UNDF && cursym.n_value) {
+               printf("definition of common %s size %d\n",
+                   cursym.n_un.n_name, cursym.n_value);
+               return;
+       }
+       for (tp = tynames; tp->ty_name; tp++)
+               if (tp->ty_value == (cursym.n_type&N_TYPE))
+                       break;
+       printf((cursym.n_type&N_TYPE) ? "definition of" : "reference to");
+       if (cursym.n_type&N_EXT)
+               printf(" external");
+       if (tp->ty_name)
+               printf(" %s", tp->ty_name);
+       printf(" %s\n", cursym.n_un.n_name);
+}
+
+#if !defined(tahoe)
+/* for machines which allow arbitrarily aligned word and longword accesses */
+#define        getw(cp)        (*(short *)(cp))
+#define        getl(cp)        (*(long *)(cp))
+#define        putw(cp, w)     (*(short *)(cp) = (w))
+#define        putl(cp, l)     (*(long *)(cp) = (l))
+#else
+short
+getw(cp)
+       char *cp;
+{
+       union {
+               short   w;
+               char    c[2];
+       } w;
+
+       w.c[0] = *cp++;
+       w.c[1] = *cp++;
+       return (w.w);
+}
+
+getl(cp)
+       char *cp;
+{
+       union {
+               long    l;
+               char    c[4];
+       } l;
+
+       l.c[0] = *cp++;
+       l.c[1] = *cp++;
+       l.c[2] = *cp++;
+       l.c[3] = *cp++;
+       return (l.l);
+}
+
+putw(cp, v)
+       char *cp;
+       short v;
+{
+       union {
+               short   w;
+               char    c[2];
+       } w;
+
+       w.w = v;
+       *cp++ = w.c[0];
+       *cp++ = w.c[1];
+}
+
+putl(cp, v)
+       char *cp;
+       long v;
+{
+       union {
+               long    l;
+               char    c[4];
+       } l;
+
+       l.l = v;
+       *cp++ = l.c[0];
+       *cp++ = l.c[1];
+       *cp++ = l.c[2];
+       *cp++ = l.c[3];
+}
+#endif
+
+/*
+ * This routine relocates the single text or data segment argument.
+ * Offsets from external symbols are resolved by adding the value
+ * of the external symbols.  Non-external reference are updated to account
+ * for the relative motion of the segments (ctrel, cdrel, ...).  If
+ * a relocation was pc-relative, then we update it to reflect the
+ * change in the positioning of the segments by adding the displacement
+ * of the referenced segment and subtracting the displacement of the
+ * current segment (creloc).
+ *
+ * If we are saving the relocation information, then we increase
+ * each relocation datum address by our base position in the new segment.
+ */
+load2td(creloc, position, b1, b2)
+       long creloc, position;
        struct biobuf *b1, *b2;
 {
        register struct nlist *sp;
        register struct local *lp;
        long tw;
        register struct relocation_info *rp, *rpend;
        struct biobuf *b1, *b2;
 {
        register struct nlist *sp;
        register struct local *lp;
        long tw;
        register struct relocation_info *rp, *rpend;
-       long address;
        struct relocation_info *relp;
        char *codep;
        register char *cp;
        struct relocation_info *relp;
        char *codep;
        register char *cp;
@@ -1170,9 +1420,10 @@ load2td(creloc, b1, b2)
        rpend = &relp[relsz / sizeof (struct relocation_info)];
        mget(codep, codesz, &text);
        for (rp = relp; rp < rpend; rp++) {
        rpend = &relp[relsz / sizeof (struct relocation_info)];
        mget(codep, codesz, &text);
        for (rp = relp; rp < rpend; rp++) {
-               if (rflag)
-                       address = rp->r_address + creloc;
                cp = codep + rp->r_address;
                cp = codep + rp->r_address;
+               /*
+                * Pick up previous value at location to be relocated.
+                */
                switch (rp->r_length) {
 
                case 0:         /* byte */
                switch (rp->r_length) {
 
                case 0:         /* byte */
@@ -1180,17 +1431,29 @@ load2td(creloc, b1, b2)
                        break;
 
                case 1:         /* word */
                        break;
 
                case 1:         /* word */
-                       tw = *(short *)cp;
+                       tw = getw(cp);
                        break;
 
                case 2:         /* long */
                        break;
 
                case 2:         /* long */
-                       tw = *(long *)cp;
+                       tw = getl(cp);
                        break;
 
                default:
                        error(1, "load2td botch: bad length");
                }
                        break;
 
                default:
                        error(1, "load2td botch: bad length");
                }
+               /*
+                * If relative to an external which is defined,
+                * resolve to a simpler kind of reference in the
+                * result file.  If the external is undefined, just
+                * convert the symbol number to the number of the
+                * symbol in the result file and leave it undefined.
+                */
                if (rp->r_extern) {
                if (rp->r_extern) {
+                       /*
+                        * Search the hash table which maps local
+                        * symbol numbers to symbol tables entries
+                        * in the new a.out file.
+                        */
                        lp = lochash[rp->r_symbolnum % LHSIZ];
                        while (lp->l_index != rp->r_symbolnum) {
                                lp = lp->l_link;
                        lp = lochash[rp->r_symbolnum % LHSIZ];
                        while (lp->l_index != rp->r_symbolnum) {
                                lp = lp->l_link;
@@ -1206,7 +1469,11 @@ load2td(creloc, b1, b2)
                                rp->r_extern = 0;
                        }
                } else switch (rp->r_symbolnum & N_TYPE) {
                                rp->r_extern = 0;
                        }
                } else switch (rp->r_symbolnum & N_TYPE) {
-
+               /*
+                * Relocation is relative to the loaded position
+                * of another segment.  Update by the change in position
+                * of that segment.
+                */
                case N_TEXT:
                        tw += ctrel;
                        break;
                case N_TEXT:
                        tw += ctrel;
                        break;
@@ -1221,9 +1488,21 @@ load2td(creloc, b1, b2)
                default:
                        error(1, "relocation format botch (symbol type))");
                }
                default:
                        error(1, "relocation format botch (symbol type))");
                }
+               /*
+                * Relocation is pc relative, so decrease the relocation
+                * by the amount the current segment is displaced.
+                * (E.g if we are a relative reference to a text location
+                * from data space, we added the increase in the text address
+                * above, and subtract the increase in our (data) address
+                * here, leaving the net change the relative change in the
+                * positioning of our text and data segments.)
+                */
                if (rp->r_pcrel)
                if (rp->r_pcrel)
-                       /* assembler already subtracted text.pos */
                        tw -= creloc;
                        tw -= creloc;
+               /*
+                * Put the value back in the segment,
+                * while checking for overflow.
+                */
                switch (rp->r_length) {
 
                case 0:         /* byte */
                switch (rp->r_length) {
 
                case 0:         /* byte */
@@ -1234,25 +1513,33 @@ load2td(creloc, b1, b2)
                case 1:         /* word */
                        if (tw < -32768 || tw > 32767)
                                error(0, "word displacement overflow");
                case 1:         /* word */
                        if (tw < -32768 || tw > 32767)
                                error(0, "word displacement overflow");
-                       *(short *)cp = tw;
+                       putw(cp, tw);
                        break;
                case 2:         /* long */
                        break;
                case 2:         /* long */
-                       *(long *)cp = tw;
+                       putl(cp, tw);
                        break;
                }
                        break;
                }
+               /*
+                * If we are saving relocation information,
+                * we must convert the address in the segment from
+                * the old .o file into an address in the segment in
+                * the new a.out, by adding the position of our
+                * segment in the new larger segment.
+                */
                if (rflag)
                if (rflag)
-                       rp->r_address = address;
+                       rp->r_address += position;
        }
        bwrite(codep, codesz, b1);
        if (rflag)
                bwrite(relp, relsz, b2);
        }
        bwrite(codep, codesz, b1);
        if (rflag)
                bwrite(relp, relsz, b2);
-       cfree((char *)relp);
-       cfree(codep);
+       free((char *)relp);
+       free(codep);
 }
 
 finishout()
 {
        register int i;
 }
 
 finishout()
 {
        register int i;
+       char *newname;
        int nsymt;
 
        if (sflag==0) {
        int nsymt;
 
        if (sflag==0) {
@@ -1262,9 +1549,11 @@ finishout()
                bwrite(&offset, sizeof offset, sout);
        }
        if (!ofilfnd) {
                bwrite(&offset, sizeof offset, sout);
        }
        if (!ofilfnd) {
-               unlink("a.out");
-               link("l.out", "a.out");
-               ofilename = "a.out";
+               newname = (char *)genbuildname("a.out");
+               unlink(newname);
+               if (link(defaultname, newname) < 0)
+                       error(1, "cannot move l.out to a.out");
+               ofilename = newname;
        }
        delarg = errlev;
        delexit();
        }
        delarg = errlev;
        delexit();
@@ -1277,7 +1566,7 @@ char *s;
        if (sflag || xflag)
                return;
        cursym.n_un.n_name = s;
        if (sflag || xflag)
                return;
        cursym.n_un.n_name = s;
-       cursym.n_type = N_TEXT;
+       cursym.n_type = N_EXT | N_FN;
        cursym.n_value = torigin;
        symwrite(&cursym, sout);
 }
        cursym.n_value = torigin;
        symwrite(&cursym, sout);
 }
@@ -1321,16 +1610,16 @@ top:
                sp->ptr = p;
                goto top;
        }
                sp->ptr = p;
                goto top;
        }
-       if (n > BUFSIZ) {
-               take = n - n % BSIZE;
-               lseek(infil, (sp->bno+1)*BSIZE, 0);
+       if (n > p_blksize) {
+               take = n - n % p_blksize;
+               lseek(infil, (sp->bno+1)<<p_blkshift, 0);
                if (take > sp->size || read(infil, loc, take) != take)
                        error(1, "premature EOF");
                loc += take;
                n -= take;
                sp->size -= take;
                sp->pos += take;
                if (take > sp->size || read(infil, loc, take) != take)
                        error(1, "premature EOF");
                loc += take;
                n -= take;
                sp->size -= take;
                sp->pos += take;
-               dseek(sp, (sp->bno+1+take/BSIZE)*BSIZE, -1);
+               dseek(sp, (sp->bno+1+(take>>p_blkshift))<<p_blkshift, -1);
                goto top;
        }
        *loc++ = get(sp);
                goto top;
        }
        *loc++ = get(sp);
@@ -1364,8 +1653,8 @@ long loc, s;
        register b, o;
        int n;
 
        register b, o;
        int n;
 
-       b = loc>>BSHIFT;
-       o = loc&BMASK;
+       b = loc>>p_blkshift;
+       o = loc&p_blkmask;
        if (o&01)
                error(1, "loader error; odd offset");
        --sp->pno->nuser;
        if (o&01)
                error(1, "loader error; odd offset");
        --sp->pno->nuser;
@@ -1375,12 +1664,12 @@ long loc, s;
                                if (page[0].bno < page[1].bno)
                                        p = &page[0];
                        p->bno = b;
                                if (page[0].bno < page[1].bno)
                                        p = &page[0];
                        p->bno = b;
-                       lseek(infil, loc & ~(long)BMASK, 0);
-                       if ((n = read(infil, p->buff, sizeof(p->buff))) < 0)
+                       lseek(infil, loc & ~(long)p_blkmask, 0);
+                       if ((n = read(infil, p->buff, p_blksize)) < 0)
                                n = 0;
                        p->nibuf = n;
                                n = 0;
                        p->nibuf = n;
-       } else
-               error(1, "botch: no pages");
+               } else
+                       error(1, "botch: no pages");
        ++p->nuser;
        sp->bno = b;
        sp->pno = p;
        ++p->nuser;
        sp->bno = b;
        sp->pno = p;
@@ -1398,7 +1687,7 @@ STREAM *asp;
 
        sp = asp;
        if ((sp->nibuf -= sizeof(char)) < 0) {
 
        sp = asp;
        if ((sp->nibuf -= sizeof(char)) < 0) {
-               dseek(sp, ((long)(sp->bno+1)<<BSHIFT), (long)-1);
+               dseek(sp, ((long)(sp->bno+1)<<p_blkshift), (long)-1);
                sp->nibuf -= sizeof(char);
        }
        if ((sp->size -= sizeof(char)) <= 0) {
                sp->nibuf -= sizeof(char);
        }
        if ((sp->size -= sizeof(char)) <= 0) {
@@ -1415,37 +1704,42 @@ STREAM *asp;
 getfile(acp)
 char *acp;
 {
 getfile(acp)
 char *acp;
 {
-       register char *cp;
        register int c;
        char arcmag[SARMAG+1];
        struct stat stb;
 
        register int c;
        char arcmag[SARMAG+1];
        struct stat stb;
 
-       cp = acp; 
-       infil = -1;
        archdr.ar_name[0] = '\0';
        archdr.ar_name[0] = '\0';
-       filname = cp;
-       if (cp[0]=='-' && cp[1]=='l') {
-               char *locfilname = "/usr/local/new/libxxxxxxxxxxxxxxx";
-               if(cp[2] == '\0')
-                       cp = "-la";
-               filname = "/usr/new/libxxxxxxxxxxxxxxx";
-               for(c=0; cp[c+2]; c++) {
-                       filname[c+12] = cp[c+2];
-                       locfilname[c+18] = cp[c+2];
-               }
-               filname[c+12] = locfilname[c+18] = '.';
-               filname[c+13] = locfilname[c+19] = 'a';
-               filname[c+14] = locfilname[c+20] = '\0';
-               if ((infil = open(filname+4, 0)) >= 0) {
-                       filname += 4;
-               } else if ((infil = open(filname, 0)) < 0) {
-                       filname = locfilname;
-               }
-       }
-       if (infil == -1 && (infil = open(filname, 0)) < 0)
+       filname = acp;
+       if (filname[0] == '-' && filname[1] == 'l')
+               infil = libopen(filname + 2, O_RDONLY);
+       else
+               infil = open((char *)genbuildname(filname), O_RDONLY);
+       if (infil < 0)
                error(1, "cannot open");
                error(1, "cannot open");
+       fstat(infil, &stb);
        page[0].bno = page[1].bno = -1;
        page[0].nuser = page[1].nuser = 0;
        page[0].bno = page[1].bno = -1;
        page[0].nuser = page[1].nuser = 0;
+       c = stb.st_blksize;
+       if (c == 0 || (c & (c - 1)) != 0) {
+               /* use default size if not a power of two */
+               c = BLKSIZE;
+       }
+       if (p_blksize != c) {
+               p_blksize = c;
+               p_blkmask = c - 1;
+               for (p_blkshift = 0; c > 1 ; p_blkshift++)
+                       c >>= 1;
+               if (page[0].buff != NULL)
+                       free(page[0].buff);
+               page[0].buff = (char *)malloc(p_blksize);
+               if (page[0].buff == NULL)
+                       error(1, "ran out of memory (getfile)");
+               if (page[1].buff != NULL)
+                       free(page[1].buff);
+               page[1].buff = (char *)malloc(p_blksize);
+               if (page[1].buff == NULL)
+                       error(1, "ran out of memory (getfile)");
+       }
        text.pno = reloc.pno = (PAGE *) &fpage;
        fpage.nuser = 2;
        dseek(&text, 0L, SARMAG);
        text.pno = reloc.pno = (PAGE *) &fpage;
        fpage.nuser = 2;
        dseek(&text, 0L, SARMAG);
@@ -1456,15 +1750,48 @@ char *acp;
        if (strcmp(arcmag, ARMAG))
                return (0);
        dseek(&text, SARMAG, sizeof archdr);
        if (strcmp(arcmag, ARMAG))
                return (0);
        dseek(&text, SARMAG, sizeof archdr);
-       if(text.size <= 0)
+       if (text.size <= 0)
                return (1);
        getarhdr();
                return (1);
        getarhdr();
-       if (strncmp(archdr.ar_name, "__.SYMDEF", sizeof(archdr.ar_name)) != 0)
+       if (strncmp(archdr.ar_name, RANLIBMAG, sizeof(archdr.ar_name)) != 0)
                return (1);
                return (1);
-       fstat(infil, &stb);
        return (stb.st_mtime > atol(archdr.ar_date) ? 3 : 2);
 }
 
        return (stb.st_mtime > atol(archdr.ar_date) ? 3 : 2);
 }
 
+/*
+ * Search for a library with given name
+ * using the directory search array.
+ */
+libopen(name, oflags)
+       char *name;
+       int oflags;
+{
+       register char *p, *cp;
+       register int i;
+       static char buf[MAXPATHLEN+1];
+       int fd = -1;
+
+       if (*name == '\0')                      /* backwards compat */
+               name = "a";
+       for (i = 0; i < ndir && fd == -1; i++) {
+               p = buf;
+               for (cp = dirs[i]; *cp; *p++ = *cp++)
+                       ;
+               *p++ = '/';
+               for (cp = "lib"; *cp; *p++ = *cp++)
+                       ;
+               for (cp = name; *cp; *p++ = *cp++)
+                       ;
+               cp = ".a";
+               while (*p++ = *cp++)
+                       ;
+               fd = open(buf, oflags);
+       }
+       if (fd != -1)
+               filname = buf;
+       return (fd);
+}
+
 struct nlist **
 lookup()
 {
 struct nlist **
 lookup()
 {
@@ -1622,6 +1949,7 @@ symreloc()
 error(n, s)
 char *s;
 {
 error(n, s)
 char *s;
 {
+
        if (errlev==0)
                printf("ld:");
        if (filname) {
        if (errlev==0)
                printf("ld:");
        if (filname) {
@@ -1652,7 +1980,7 @@ off_t loc;
        if (filhdr.a_text&01 || filhdr.a_data&01)
                error(1, "text/data size odd");
        if (filhdr.a_magic == NMAGIC || filhdr.a_magic == ZMAGIC) {
        if (filhdr.a_text&01 || filhdr.a_data&01)
                error(1, "text/data size odd");
        if (filhdr.a_magic == NMAGIC || filhdr.a_magic == ZMAGIC) {
-               cdrel = -round(filhdr.a_text, PAGSIZ);
+               cdrel = -round(filhdr.a_text, pagesize);
                cbrel = cdrel - filhdr.a_data;
        } else if (filhdr.a_magic == OMAGIC) {
                cdrel = -filhdr.a_text;
                cbrel = cdrel - filhdr.a_data;
        } else if (filhdr.a_magic == OMAGIC) {
                cdrel = -filhdr.a_text;
@@ -1687,7 +2015,7 @@ savestr(cp)
                saveleft = NSAVETAB;
                if (len > saveleft)
                        saveleft = len;
                saveleft = NSAVETAB;
                if (len > saveleft)
                        saveleft = len;
-               savetab = (char *)malloc(saveleft);
+               savetab = malloc(saveleft);
                if (savetab == 0)
                        error(1, "ran out of memory (savestr)");
        }
                if (savetab == 0)
                        error(1, "ran out of memory (savestr)");
        }
@@ -1698,12 +2026,15 @@ savestr(cp)
        return (cp);
 }
 
        return (cp);
 }
 
-bopen(bp, off)
-       struct biobuf *bp;
+bopen(bp, off, bufsize)
+       register struct biobuf *bp;
 {
 
 {
 
-       bp->b_ptr = bp->b_buf;
-       bp->b_nleft = BUFSIZ - off % BUFSIZ;
+       bp->b_ptr = bp->b_buf = malloc(bufsize);
+       if (bp->b_ptr == (char *)0)
+               error(1, "ran out of memory (bopen)");
+       bp->b_bufsize = bufsize;
+       bp->b_nleft = bufsize - (off % bufsize);
        bp->b_off = off;
        bp->b_link = biobufs;
        biobufs = bp;
        bp->b_off = off;
        bp->b_link = biobufs;
        biobufs = bp;
@@ -1728,16 +2059,16 @@ top:
                        put = cnt;
                bp->b_nleft -= put;
                to = bp->b_ptr;
                        put = cnt;
                bp->b_nleft -= put;
                to = bp->b_ptr;
-               asm("movc3 r8,(r11),(r7)");
+               bcopy(p, to, put);
                bp->b_ptr += put;
                p += put;
                cnt -= put;
                goto top;
        }
                bp->b_ptr += put;
                p += put;
                cnt -= put;
                goto top;
        }
-       if (cnt >= BUFSIZ) {
+       if (cnt >= bp->b_bufsize) {
                if (bp->b_ptr != bp->b_buf)
                        bflush1(bp);
                if (bp->b_ptr != bp->b_buf)
                        bflush1(bp);
-               put = cnt - cnt % BUFSIZ;
+               put = cnt - cnt % bp->b_bufsize;
                if (boffset != bp->b_off)
                        lseek(biofd, bp->b_off, 0);
                if (write(biofd, p, put) != put) {
                if (boffset != bp->b_off)
                        lseek(biofd, bp->b_off, 0);
                if (write(biofd, p, put) != put) {
@@ -1780,7 +2111,7 @@ bflush1(bp)
        bp->b_off += cnt;
        boffset = bp->b_off;
        bp->b_ptr = bp->b_buf;
        bp->b_off += cnt;
        boffset = bp->b_off;
        bp->b_ptr = bp->b_buf;
-       bp->b_nleft = BUFSIZ;
+       bp->b_nleft = bp->b_bufsize;
 }
 
 bflushc(bp, c)
 }
 
 bflushc(bp, c)
@@ -1790,3 +2121,13 @@ bflushc(bp, c)
        bflush1(bp);
        bputc(c, bp);
 }
        bflush1(bp);
        bputc(c, bp);
 }
+
+bseek(bp, off)
+       register struct biobuf *bp;
+       register off_t off;
+{
+       bflush1(bp);
+       
+       bp->b_nleft = bp->b_bufsize - (off % bp->b_bufsize);
+       bp->b_off = off;
+}