new version from Chris Torek
[unix-history] / usr / src / old / ld / ld.c
index d48d009..ab714d0 100644 (file)
@@ -1,17 +1,32 @@
-static char sccsid[] = "@(#)ld.c 3.2 %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>
+#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.10 (Berkeley) %G%";
+#endif not lint
+
+/*
+ * ld - string table version for VAX
+ */
+
+#include <sys/param.h>
 #include <signal.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <ar.h>
 #include <a.out.h>
 #include <ranlib.h>
 #include <signal.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <ar.h>
 #include <a.out.h>
 #include <ranlib.h>
-#include <stat.h>
-#include <pagsiz.h>
+#include <sys/stat.h>
+#include <sys/file.h>
 
 /*
  * Basic strategy:
 
 /*
  * Basic strategy:
@@ -170,16 +185,23 @@ char      *tabstr;        /* string table for table of contents */
  * (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''.
  * (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''.
+ * 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;
@@ -217,6 +239,7 @@ 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    zflag;          /* demand paged  */
 int    nflag;          /* pure procedure */
 int    dflag;          /* define common even with rflag */
 int    zflag;          /* demand paged  */
@@ -224,6 +247,8 @@ 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    Aflag;          /* doing incremental load */
 int    Nflag;          /* want impure a.out */
 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
@@ -273,9 +298,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;
@@ -295,17 +321,29 @@ off_t     offset = sizeof (off_t);
 
 int    ofilfnd;                /* -o given; otherwise move l.out to a.out */
 char   *ofilename = "l.out";
 
 int    ofilfnd;                /* -o given; otherwise move l.out to a.out */
 char   *ofilename = "l.out";
+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;
@@ -321,8 +359,27 @@ char **argv;
        }
        if (argc == 1)
                exit(4);
        }
        if (argc == 1)
                exit(4);
-       p = argv+1;
+       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++] = "/lib";
+       dirs[ndir++] = "/usr/lib";
+       dirs[ndir++] = "/usr/local/lib";
+
+       p = argv+1;
        /*
         * Scan files once to find where symbols are defined.
         */
        /*
         * Scan files once to find where symbols are defined.
         */
@@ -346,7 +403,7 @@ char **argv;
                case 'u':
                case 'e':
                        if (++c >= argc)
                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;
@@ -393,6 +450,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;
@@ -427,10 +487,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++;
                        Nflag = nflag = 0;
                        continue;
                case 'z':
                        zflag++;
                        Nflag = nflag = 0;
                        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 */
@@ -472,11 +544,29 @@ htoi(p)
 
 delexit()
 {
 
 delexit()
 {
+       struct stat stbuf;
+       long size;
+       char c = 0;
 
        bflush();
        unlink("l.out");
 
        bflush();
        unlink("l.out");
+       /*
+        * 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);
 }
 
@@ -525,6 +615,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]);
@@ -544,8 +637,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.
@@ -559,7 +656,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) +
@@ -601,8 +699,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;
 
@@ -611,7 +709,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) +
@@ -660,6 +759,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);
 }
 
 /*
 }
 
 /*
@@ -678,7 +779,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)
@@ -706,8 +807,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)
@@ -828,7 +933,7 @@ 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) {
                ldrsym(p_etext, tsize, N_EXT+N_TEXT);
        database += hsize;
        if (dflag || rflag==0) {
                ldrsym(p_etext, tsize, N_EXT+N_TEXT);
@@ -871,7 +976,8 @@ 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 (sp==p_end || sp==p_etext || sp==p_edata)
                                        continue;
                        if ((arflag==0 || dflag) && sp->n_value==0) {
                                if (sp==p_end || sp==p_etext || sp==p_edata)
                                        continue;
@@ -941,16 +1047,26 @@ struct   biobuf toutb;
 setupout()
 {
        int bss;
 setupout()
 {
        int bss;
-
-       biofd = creat(ofilename, 0666);
-       if (biofd < 0)
-               error(1, "cannot create output");
-       tout = &toutb;
-       bopen(tout, 0);
+       struct stat stbuf;
+       extern char *sys_errlist[];
+       extern int errno;
+
+       ofilemode = 0777 & ~umask(0);
+       biofd = creat(ofilename, 0666 & ofilemode);
+       if (biofd < 0) {
+               filname = ofilename;            /* kludge */
+               archdr.ar_name[0] = 0;          /* kludge */
+               error(1, sys_errlist[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;
@@ -967,33 +1083,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;
 }
 
@@ -1098,6 +1213,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))
@@ -1148,11 +1271,117 @@ long loc;
                filhdr.a_data++;
        }
        torigin += filhdr.a_text;
                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);
 }
 
+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
 /*
  * This routine relocates the single text or data segment argument.
  * Offsets from external symbols are resolved by adding the value
@@ -1167,7 +1396,7 @@ long loc;
  * each relocation datum address by our base position in the new segment.
  */
 load2td(creloc, position, b1, b2)
  * each relocation datum address by our base position in the new segment.
  */
 load2td(creloc, position, b1, b2)
-       long creloc, offset;
+       long creloc, position;
        struct biobuf *b1, *b2;
 {
        register struct nlist *sp;
        struct biobuf *b1, *b2;
 {
        register struct nlist *sp;
@@ -1200,11 +1429,11 @@ load2td(creloc, position, 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:
                        break;
 
                default:
@@ -1282,10 +1511,10 @@ load2td(creloc, position, 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;
                }
                /*
@@ -1301,8 +1530,8 @@ load2td(creloc, position, b1, b2)
        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()
 }
 
 finishout()
@@ -1318,7 +1547,8 @@ finishout()
        }
        if (!ofilfnd) {
                unlink("a.out");
        }
        if (!ofilfnd) {
                unlink("a.out");
-               link("l.out", "a.out");
+               if (link("l.out", "a.out") < 0)
+                       error(1, "cannot move l.out to a.out");
                ofilename = "a.out";
        }
        delarg = errlev;
                ofilename = "a.out";
        }
        delarg = errlev;
@@ -1332,7 +1562,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);
 }
@@ -1376,16 +1606,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);
@@ -1419,8 +1649,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;
@@ -1430,12 +1660,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;
@@ -1453,7 +1683,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) {
@@ -1470,37 +1700,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(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);
@@ -1511,15 +1746,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()
 {
@@ -1677,6 +1945,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) {
@@ -1707,7 +1976,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;
@@ -1742,7 +2011,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)");
        }
@@ -1753,12 +2022,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;
@@ -1783,16 +2055,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) {
@@ -1835,7 +2107,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)
@@ -1845,3 +2117,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;
+}