Research V7 development
authorDennis Ritchie <dmr@research.uucp>
Tue, 15 May 1979 22:24:39 +0000 (17:24 -0500)
committerDennis Ritchie <dmr@research.uucp>
Tue, 15 May 1979 22:24:39 +0000 (17:24 -0500)
Work on file usr/src/cmd/ld.c

Synthesized-from: v7

usr/src/cmd/ld.c [new file with mode: 0644]

diff --git a/usr/src/cmd/ld.c b/usr/src/cmd/ld.c
new file mode 100644 (file)
index 0000000..48f52a9
--- /dev/null
@@ -0,0 +1,1298 @@
+/*
+ *  link editor
+ */
+
+#include <signal.h>
+#include "sys/types.h"
+#include "sys/stat.h"
+
+/*     Layout of a.out file :
+ *
+ *     header of 8 words       magic number 405, 407, 410, 411
+ *                             text size       )
+ *                             data size       ) in bytes but even
+ *                             bss size        )
+ *                             symbol table size
+ *                             entry point
+ *                             {unused}
+ *                             flag set if no relocation
+ *
+ *
+ *     header:         0
+ *     text:           16
+ *     data:           16+textsize
+ *     relocation:     16+textsize+datasize
+ *     symbol table:   16+2*(textsize+datasize) or 16+textsize+datasize
+ *
+ */
+#define TRUE   1
+#define FALSE  0
+
+
+#define        ARCMAGIC 0177545
+#define OMAGIC 0405
+#define        FMAGIC  0407
+#define        NMAGIC  0410
+#define        IMAGIC  0411
+
+#define        EXTERN  040
+#define        UNDEF   00
+#define        ABS     01
+#define        TEXT    02
+#define        DATA    03
+#define        BSS     04
+#define        COMM    05      /* internal use only */
+
+#define        RABS    00
+#define        RTEXT   02
+#define        RDATA   04
+#define        RBSS    06
+#define        REXT    010
+
+#define NOVLY  16
+#define        RELFLG  01
+#define        NROUT   256
+#define        NSYM    1103
+#define        NSYMPR  1000
+
+char   premeof[] = "Premature EOF";
+char   goodnm[] = "__.SYMDEF";
+
+/* table of contents stuff */
+#define TABSZ  700
+struct tab
+{      char cname[8];
+       long cloc;
+} tab[TABSZ];
+int tnum;
+
+
+/* overlay management */
+int    vindex;
+struct overlay {
+       int     argsav;
+       int     symsav;
+       struct liblist  *libsav;
+       char    *vname;
+       int     ctsav, cdsav, cbsav;
+       int     offt, offd, offb, offs;
+} vnodes[NOVLY];
+
+/* input management */
+struct page {
+       int     nuser;
+       int     bno;
+       int     nibuf;
+       int     buff[256];
+} page[2];
+
+struct {
+       int     nuser;
+       int     bno;
+} fpage;
+
+struct stream {
+       int     *ptr;
+       int     bno;
+       int     nibuf;
+       int     size;
+       struct page     *pno;
+};
+
+struct stream text;
+struct stream reloc;
+
+struct {
+       char    aname[14];
+       long    atime;
+       char    auid, agid;
+       int     amode;
+       long    asize;
+} archdr;
+
+struct {
+       int     fmagic;
+       int     tsize;
+       int     dsize;
+       int     bsize;
+       int     ssize;
+       int     entry;
+       int     pad;
+       int     relflg;
+} filhdr;
+
+
+/* one entry for each archive member referenced;
+ * set in first pass; needs restoring for overlays
+ */
+struct liblist {
+       long    loc;
+};
+
+struct liblist liblist[NROUT];
+struct liblist *libp = liblist;
+
+
+/* symbol management */
+struct symbol {
+       char    sname[8];
+       char    stype;
+       char    spare;
+       int     svalue;
+};
+
+struct local {
+       int locindex;           /* index to symbol in file */
+       struct symbol *locsymbol;       /* ptr to symbol table */
+};
+
+struct symbol  cursym;                 /* current symbol */
+struct symbol  symtab[NSYM];           /* actual symbols */
+struct symbol  **symhash[NSYM];        /* ptr to hash table entry */
+struct symbol  *lastsym;               /* last symbol entered */
+int    symindex;               /* next available symbol table entry */
+struct symbol  *hshtab[NSYM+2];        /* hash table for symbols */
+struct local   local[NSYMPR];
+
+/* internal symbols */
+struct symbol  *p_etext;
+struct symbol  *p_edata;
+struct symbol  *p_end;
+struct symbol  *entrypt;
+
+int    trace;
+/* flags */
+int    xflag;          /* discard local symbols */
+int    Xflag;          /* discard locals starting with 'L' */
+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    nflag;          /* pure procedure */
+int    Oflag;          /* set magic # to 0405 (overlay) */
+int    dflag;          /* define common even with rflag */
+int    iflag;          /* I/D space separated */
+int    vflag;          /* overlays used */
+
+int    ofilfnd;
+char   *ofilename = "l.out";
+int    infil;
+char   *filname;
+
+/* cumulative sizes set in pass 1 */
+int    tsize;
+int    dsize;
+int    bsize;
+int    ssize;
+
+/* symbol relocation; both passes */
+int    ctrel;
+int    cdrel;
+int    cbrel;
+
+int    errlev;
+int    delarg  = 4;
+char   tfname[] = "/tmp/ldaXXXXX";
+
+
+/* output management */
+struct buf {
+       int     fildes;
+       int     nleft;
+       int     *xnext;
+       int     iobuf[256];
+};
+struct buf     toutb;
+struct buf     doutb;
+struct buf     troutb;
+struct buf     droutb;
+struct buf     soutb;
+
+struct symbol  **lookup();
+struct symbol  **slookup();
+struct symbol  *lookloc();
+
+delexit()
+{
+       unlink("l.out");
+       if (delarg==0)
+               chmod(ofilename, 0777 & ~umask(0));
+       exit(delarg);
+}
+
+main(argc, argv)
+char **argv;
+{
+       register int c, i; 
+       int num;
+       register char *ap, **p;
+       int found; 
+       int vscan; 
+       char save;
+
+       if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+               signal(SIGINT, delexit);
+       if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
+               signal(SIGTERM, delexit);
+       if (argc == 1)
+               exit(4);
+       p = argv+1;
+
+       /* scan files once to find symdefs */
+       for (c=1; c<argc; c++) {
+               if (trace) printf("%s:\n", *p);
+               filname = 0;
+               ap = *p++;
+
+               if (*ap == '-') {
+                       for (i=1; ap[i]; i++) {
+                       switch (ap[i]) {
+                       case 'o':
+                               if (++c >= argc)
+                                       error(2, "Bad output file");
+                               ofilename = *p++;
+                               ofilfnd++;
+                               continue;
+
+                       case 'u':
+                       case 'e':
+                               if (++c >= argc)
+                                       error(2, "Bad 'use' or 'entry'");
+                               enter(slookup(*p++));
+                               if (ap[i]=='e')
+                                       entrypt = lastsym;
+                               continue;
+
+                       case 'v':
+                               if (++c >= argc)
+                                       error(2, "-v: arg missing");
+                               vflag=TRUE;
+                               vscan = vindex; 
+                               found=FALSE;
+                               while (--vscan>=0 && found==FALSE)
+                                       found = eq(vnodes[vscan].vname, *p);
+                               if (found) {
+                                       endload(c, argv);
+                                       restore(vscan);
+                               } else
+                                       record(c, *p);
+                               p++;
+                               continue;
+
+                       case 'D':
+                               if (++c >= argc)
+                                       error(2, "-D: arg missing");
+                               num = atoi(*p++);
+                               if (dsize>num)
+                                       error(2, "-D: too small");
+                               dsize = num;
+                               continue;
+
+                       case 'l':
+                               save = ap[--i]; 
+                               ap[i]='-';
+                               load1arg(&ap[i]); 
+                               ap[i]=save;
+                               break;
+
+                       case 'x':
+                               xflag++;
+                               continue;
+
+                       case 'X':
+                               Xflag++;
+                               continue;
+
+                       case 'S':
+                               Sflag++; 
+                               continue;
+
+                       case 'r':
+                               rflag++;
+                               arflag++;
+                               continue;
+
+                       case 's':
+                               sflag++;
+                               xflag++;
+                               continue;
+
+                       case 'n':
+                               nflag++;
+                               continue;
+
+                       case 'd':
+                               dflag++;
+                               continue;
+
+                       case 'i':
+                               iflag++;
+                               continue;
+
+                       case 'O':
+                               Oflag++;
+                               continue;
+
+                       case 't':
+                               trace++;
+                               continue;
+
+                       default:
+                               error(2, "bad flag");
+                       } /*endsw*/
+                       break;
+                       } /*endfor*/
+               } else
+                       load1arg(ap);
+       }
+       endload(argc, argv);
+}
+
+/* used after pass 1 */
+int    nsym;
+int    torigin;
+int    dorigin;
+int    borigin;
+
+endload(argc, argv)
+int argc; 
+char **argv;
+{
+       register int c, i; 
+       int dnum;
+       register char *ap, **p;
+       filname = 0;
+       middle();
+       setupout();
+       p = argv+1;
+       libp = liblist;
+       for (c=1; c<argc; c++) {
+               ap = *p++;
+               if (trace) printf("%s:\n", ap);
+               if (*ap == '-') {
+                       for (i=1; ap[i]; i++) {
+                       switch (ap[i]) {
+                       case 'D':
+                               for (dnum = atoi(*p); dorigin<dnum; dorigin += 2) {
+                                       putw(0, &doutb);
+                                       if (rflag)
+                                               putw(0, &droutb);
+                               }
+                       case 'u':
+                       case 'e':
+                       case 'o':
+                       case 'v':
+                               ++c; 
+                               ++p;
+
+                       default:
+                               continue;
+
+                       case 'l':
+                               ap[--i]='-'; 
+                               load2arg(&ap[i]);
+                               break;
+                       } /*endsw*/
+                       break;
+                       } /*endfor*/
+               } else
+                       load2arg(ap);
+       }
+       finishout();
+}
+
+record(c, nam)
+int c; 
+char *nam;
+{
+       register struct overlay *v;
+
+       v = &vnodes[vindex++];
+       v->argsav = c;
+       v->symsav = symindex;
+       v->libsav = libp;
+       v->vname = nam;
+       v->offt = tsize; 
+       v->offd = dsize; 
+       v->offb = bsize; 
+       v->offs = ssize;
+       v->ctsav = ctrel; 
+       v->cdsav = cdrel; 
+       v->cbsav = cbrel;
+}
+
+restore(vscan)
+int vscan;
+{
+       register struct overlay *v;
+       register int saved;
+
+       v = &vnodes[vscan];
+       vindex = vscan+1;
+       libp = v->libsav;
+       ctrel = v->ctsav; 
+       cdrel = v->cdsav; 
+       cbrel = v->cbsav;
+       tsize = v->offt; 
+       dsize = v->offd; 
+       bsize = v->offb; 
+       ssize = v->offs;
+       saved = v->symsav;
+       while (symindex>saved)
+               *symhash[--symindex]=0;
+}
+
+/* scan file to find defined symbols */
+load1arg(acp)
+char *acp;
+{
+       register char *cp;
+       long nloc;
+
+       cp = acp;
+       switch ( getfile(cp)) {
+       case 0:
+               load1(0, 0L);
+               break;
+
+       /* regular archive */
+       case 1:
+               nloc = 1;
+               while ( step(nloc))
+                       nloc += (archdr.asize + sizeof(archdr) + 1) >> 1;
+               break;
+
+       /* table of contents */
+       case 2:
+               tnum = archdr.asize / sizeof(struct tab);
+               if (tnum >= TABSZ) {
+                       error(2, "fast load buffer too small");
+               }
+               lseek(infil, (long)(sizeof(filhdr.fmagic)+sizeof(archdr)), 0);
+               read(infil, (char *)tab, tnum * sizeof(struct tab));
+               while (ldrand());
+               libp->loc = -1;
+               libp++;
+               break;
+       /* out of date table of contents */
+       case 3:
+               error(0, "out of date (warning)");
+               for(nloc = 1+((archdr.asize+sizeof(archdr)+1) >> 1); step(nloc);
+                       nloc += (archdr.asize + sizeof(archdr) + 1) >> 1);
+               break;
+       }
+       close(infil);
+}
+
+step(nloc)
+long nloc;
+{
+       dseek(&text, nloc, sizeof archdr);
+       if (text.size <= 0) {
+               libp->loc = -1;
+               libp++;
+               return(0);
+       }
+       mget((int *)&archdr, sizeof archdr);
+       if (load1(1, nloc + (sizeof archdr) / 2)) {
+               libp->loc = nloc;
+               libp++;
+       }
+       return(1);
+}
+
+ldrand()
+{
+       int i;
+       struct symbol *sp, **pp;
+       struct liblist *oldp = libp;
+       for(i = 0; i<tnum; i++) {
+               if ((pp = slookup(tab[i].cname)) == 0)
+                       continue;
+               sp = *pp;
+               if (sp->stype != EXTERN+UNDEF)
+                       continue;
+               step(tab[i].cloc >> 1);
+       }
+       return(oldp != libp);
+}
+
+add(a,b,s)
+int a, b;
+char *s;
+{
+       long r;
+
+       r = (long)(unsigned)a + (unsigned)b;
+       if (r >= 0200000)
+               error(1,s);
+       return(r);
+}
+
+
+/* single file or archive member */
+load1(libflg, loc)
+long loc;
+{
+       register struct symbol *sp;
+       int savindex;
+       int ndef, nloc, type, mtype;
+
+       readhdr(loc);
+       ctrel = tsize;
+       cdrel += dsize;
+       cbrel += bsize;
+       ndef = 0;
+       nloc = sizeof cursym;
+       savindex = symindex;
+       if ((filhdr.relflg&RELFLG)==1) {
+               error(1, "No relocation bits");
+               return(0);
+       }
+       loc += (sizeof filhdr)/2 + filhdr.tsize + filhdr.dsize;
+       dseek(&text, loc, filhdr.ssize);
+       while (text.size > 0) {
+               mget((int *)&cursym, sizeof cursym);
+               type = cursym.stype;
+               if (Sflag) {
+                       mtype = type&037;
+                       if (mtype==1 || mtype>4) {
+                               continue;
+                       }
+               }
+               if ((type&EXTERN)==0) {
+                       if (Xflag==0 || cursym.sname[0]!='L')
+                               nloc += sizeof cursym;
+                       continue;
+               }
+               symreloc();
+               if (enter(lookup()))
+                       continue;
+               if ((sp = lastsym)->stype != EXTERN+UNDEF)
+                       continue;
+               if (cursym.stype == EXTERN+UNDEF) {
+                       if (cursym.svalue > sp->svalue)
+                               sp->svalue = cursym.svalue;
+                       continue;
+               }
+               if (sp->svalue != 0 && cursym.stype == EXTERN+TEXT)
+                       continue;
+               ndef++;
+               sp->stype = cursym.stype;
+               sp->svalue = cursym.svalue;
+       }
+       if (libflg==0 || ndef) {
+               tsize = add(tsize,filhdr.tsize,"text overflow");
+               dsize = add(dsize,filhdr.dsize,"data overflow");
+               bsize = add(bsize,filhdr.bsize,"bss overflow");
+               ssize = add(ssize,nloc,"symbol table overflow");
+               return(1);
+       }
+       /*
+        * No symbols defined by this library member.
+        * Rip out the hash table entries and reset the symbol table.
+        */
+       while (symindex>savindex)
+               *symhash[--symindex]=0;
+       return(0);
+}
+
+middle()
+{
+       register struct symbol *sp, *symp;
+       register t, csize;
+       int nund, corigin;
+
+       torigin=0; 
+       dorigin=0; 
+       borigin=0;
+
+       p_etext = *slookup("_etext");
+       p_edata = *slookup("_edata");
+       p_end = *slookup("_end");
+       /*
+        * If there are any undefined symbols, save the relocation bits.
+        */
+       symp = &symtab[symindex];
+       if (rflag==0) {
+               for (sp = symtab; sp<symp; sp++)
+                       if (sp->stype==EXTERN+UNDEF && sp->svalue==0
+                               && sp!=p_end && sp!=p_edata && sp!=p_etext) {
+                               rflag++;
+                               dflag = 0;
+                               break;
+                       }
+       }
+       if (rflag)
+               nflag = sflag = iflag = Oflag = 0;
+       /*
+        * Assign common locations.
+        */
+       csize = 0;
+       if (dflag || rflag==0) {
+               ldrsym(p_etext, tsize, EXTERN+TEXT);
+               ldrsym(p_edata, dsize, EXTERN+DATA);
+               ldrsym(p_end, bsize, EXTERN+BSS);
+               for (sp = symtab; sp<symp; sp++)
+                       if (sp->stype==EXTERN+UNDEF && (t = sp->svalue)!=0) {
+                               t = (t+1) & ~01;
+                               sp->svalue = csize;
+                               sp->stype = EXTERN+COMM;
+                               csize = add(csize, t, "bss overflow");
+                       }
+       }
+       /*
+        * Now set symbols to their final value
+        */
+       if (nflag || iflag)
+               tsize = (tsize + 077) & ~077;
+       dorigin = tsize;
+       if (nflag)
+               dorigin = (tsize+017777) & ~017777;
+       if (iflag)
+               dorigin = 0;
+       corigin = dorigin + dsize;
+       borigin = corigin + csize;
+       nund = 0;
+       for (sp = symtab; sp<symp; sp++) switch (sp->stype) {
+       case EXTERN+UNDEF:
+               errlev |= 01;
+               if (arflag==0 && sp->svalue==0) {
+                       if (nund==0)
+                               printf("Undefined:\n");
+                       nund++;
+                       printf("%.8s\n", sp->sname);
+               }
+               continue;
+
+       case EXTERN+ABS:
+       default:
+               continue;
+
+       case EXTERN+TEXT:
+               sp->svalue += torigin;
+               continue;
+
+       case EXTERN+DATA:
+               sp->svalue += dorigin;
+               continue;
+
+       case EXTERN+BSS:
+               sp->svalue += borigin;
+               continue;
+
+       case EXTERN+COMM:
+               sp->stype = EXTERN+BSS;
+               sp->svalue += corigin;
+               continue;
+       }
+       if (sflag || xflag)
+               ssize = 0;
+       bsize = add(bsize, csize, "bss overflow");
+       nsym = ssize / (sizeof cursym);
+}
+
+ldrsym(asp, val, type)
+struct symbol *asp;
+{
+       register struct symbol *sp;
+
+       if ((sp = asp) == 0)
+               return;
+       if (sp->stype != EXTERN+UNDEF || sp->svalue) {
+               printf("%.8s: ", sp->sname);
+               error(1, "Multiply defined");
+               return;
+       }
+       sp->stype = type;
+       sp->svalue = val;
+}
+
+setupout()
+{
+       tcreat(&toutb, 0);
+       mktemp(tfname);
+       tcreat(&doutb, 1);
+       if (sflag==0 || xflag==0)
+               tcreat(&soutb, 1);
+       if (rflag) {
+               tcreat(&troutb, 1);
+               tcreat(&droutb, 1);
+       }
+       filhdr.fmagic = (Oflag ? OMAGIC :( iflag ? IMAGIC : ( nflag ? NMAGIC : FMAGIC )));
+       filhdr.tsize = tsize;
+       filhdr.dsize = dsize;
+       filhdr.bsize = bsize;
+       filhdr.ssize = sflag? 0: (ssize + (sizeof cursym)*symindex);
+       if (entrypt) {
+               if (entrypt->stype!=EXTERN+TEXT)
+                       error(1, "Entry point not in text");
+               else
+                       filhdr.entry = entrypt->svalue | 01;
+       } else
+               filhdr.entry=0;
+       filhdr.pad = 0;
+       filhdr.relflg = (rflag==0);
+       mput(&toutb, (int *)&filhdr, sizeof filhdr);
+}
+
+tcreat(buf, tempflg)
+struct buf *buf;
+{
+       register int ufd; 
+       char *nam;
+       nam = (tempflg ? tfname : ofilename);
+       if ((ufd = creat(nam, 0666)) < 0)
+               error(2, tempflg?"cannot create temp":"cannot create output");
+       close(ufd); 
+       buf->fildes = open(nam, 2);
+       if (tempflg)
+               unlink(tfname);
+       buf->nleft = sizeof(buf->iobuf)/sizeof(int);
+       buf->xnext = buf->iobuf;
+}
+
+load2arg(acp)
+char *acp;
+{
+       register char *cp;
+       register struct liblist *lp;
+
+       cp = acp;
+       if (getfile(cp) == 0) {
+               while (*cp)
+                       cp++;
+               while (cp >= acp && *--cp != '/');
+               mkfsym(++cp);
+               load2(0L);
+       } else {        /* scan archive members referenced */
+               for (lp = libp; lp->loc != -1; lp++) {
+                       dseek(&text, lp->loc, sizeof archdr);
+                       mget((int *)&archdr, sizeof archdr);
+                       mkfsym(archdr.aname);
+                       load2(lp->loc + (sizeof archdr) / 2);
+               }
+               libp = ++lp;
+       }
+       close(infil);
+}
+
+load2(loc)
+long loc;
+{
+       register struct symbol *sp;
+       register struct local *lp;
+       register int symno;
+       int type, mtype;
+
+       readhdr(loc);
+       ctrel = torigin;
+       cdrel += dorigin;
+       cbrel += borigin;
+       /*
+        * Reread the symbol table, recording the numbering
+        * of symbols for fixing external references.
+        */
+       lp = local;
+       symno = -1;
+       loc += (sizeof filhdr)/2;
+       dseek(&text, loc + filhdr.tsize + filhdr.dsize, filhdr.ssize);
+       while (text.size > 0) {
+               symno++;
+               mget((int *)&cursym, sizeof cursym);
+               symreloc();
+               type = cursym.stype;
+               if (Sflag) {
+                       mtype = type&037;
+                       if (mtype==1 || mtype>4) continue;
+               }
+               if ((type&EXTERN) == 0) {
+                       if (!sflag&&!xflag&&(!Xflag||cursym.sname[0]!='L'))
+                               mput(&soutb, (int *)&cursym, sizeof cursym);
+                       continue;
+               }
+               if ((sp = *lookup()) == 0)
+                       error(2, "internal error: symbol not found");
+               if (cursym.stype == EXTERN+UNDEF) {
+                       if (lp >= &local[NSYMPR])
+                               error(2, "Local symbol overflow");
+                       lp->locindex = symno;
+                       lp++->locsymbol = sp;
+                       continue;
+               }
+               if (cursym.stype!=sp->stype || cursym.svalue!=sp->svalue) {
+                       printf("%.8s: ", cursym.sname);
+                       error(1, "Multiply defined");
+               }
+       }
+       dseek(&text, loc, filhdr.tsize);
+       dseek(&reloc, loc + half(filhdr.tsize + filhdr.dsize), filhdr.tsize);
+       load2td(lp, ctrel, &toutb, &troutb);
+       dseek(&text, loc+half(filhdr.tsize), filhdr.dsize);
+       dseek(&reloc, loc+filhdr.tsize+half(filhdr.dsize), filhdr.dsize);
+       load2td(lp, cdrel, &doutb, &droutb);
+       torigin += filhdr.tsize;
+       dorigin += filhdr.dsize;
+       borigin += filhdr.bsize;
+}
+
+load2td(lp, creloc, b1, b2)
+struct local *lp;
+struct buf *b1, *b2;
+{
+       register r, t;
+       register struct symbol *sp;
+
+       for (;;) {
+               /*
+                        * The pickup code is copied from "get" for speed.
+                        */
+
+               /* next text or data word */
+               if (--text.size <= 0) {
+                       if (text.size < 0)
+                               break;
+                       text.size++;
+                       t = get(&text);
+               } else if (--text.nibuf < 0) {
+                       text.nibuf++;
+                       text.size++;
+                       t = get(&text);
+               } else
+                       t = *text.ptr++;
+
+               /* next relocation word */
+               if (--reloc.size <= 0) {
+                       if (reloc.size < 0)
+                               error(2, "Relocation error");
+                       reloc.size++;
+                       r = get(&reloc);
+               } else if (--reloc.nibuf < 0) {
+                       reloc.nibuf++;
+                       reloc.size++;
+                       r = get(&reloc);
+               } else
+                       r = *reloc.ptr++;
+
+               switch (r&016) {
+
+               case RTEXT:
+                       t += ctrel;
+                       break;
+
+               case RDATA:
+                       t += cdrel;
+                       break;
+
+               case RBSS:
+                       t += cbrel;
+                       break;
+
+               case REXT:
+                       sp = lookloc(lp, r);
+                       if (sp->stype==EXTERN+UNDEF) {
+                               r = (r&01) + ((nsym+(sp-symtab))<<4) + REXT;
+                               break;
+                       }
+                       t += sp->svalue;
+                       r = (r&01) + ((sp->stype-(EXTERN+ABS))<<1);
+                       break;
+               }
+               if (r&01)
+                       t -= creloc;
+               putw(t, b1);
+               if (rflag)
+                       putw(r, b2);
+       }
+}
+
+finishout()
+{
+       register n, *p;
+
+       if (nflag||iflag) {
+               n = torigin;
+               while (n&077) {
+                       n += 2;
+                       putw(0, &toutb);
+                       if (rflag)
+                               putw(0, &troutb);
+               }
+       }
+       copy(&doutb);
+       if (rflag) {
+               copy(&troutb);
+               copy(&droutb);
+       }
+       if (sflag==0) {
+               if (xflag==0)
+                       copy(&soutb);
+               for (p = (int *)symtab; p < (int *)&symtab[symindex];)
+                       putw(*p++, &toutb);
+       }
+       flush(&toutb);
+       close(toutb.fildes);
+       if (!ofilfnd) {
+               unlink("a.out");
+               link("l.out", "a.out");
+               ofilename = "a.out";
+       }
+       delarg = errlev;
+       delexit();
+}
+
+copy(buf)
+struct buf *buf;
+{
+       register f, *p, n;
+
+       flush(buf);
+       lseek(f = buf->fildes, (long)0, 0);
+       while ((n = read(f, (char *)doutb.iobuf, sizeof(doutb.iobuf))) > 1) {
+               n >>= 1;
+               p = (int *)doutb.iobuf;
+               do
+                       putw(*p++, &toutb);
+               while (--n);
+       }
+       close(f);
+}
+
+mkfsym(s)
+char *s;
+{
+
+       if (sflag || xflag)
+               return;
+       cp8c(s, cursym.sname);
+       cursym.stype = 037;
+       cursym.svalue = torigin;
+       mput(&soutb, (int *)&cursym, sizeof cursym);
+}
+
+mget(aloc, an)
+int *aloc;
+{
+       register *loc, n;
+       register *p;
+
+       n = an;
+       n >>= 1;
+       loc = aloc;
+       if ((text.nibuf -= n) >= 0) {
+               if ((text.size -= n) > 0) {
+                       p = text.ptr;
+                       do
+                               *loc++ = *p++;
+                       while (--n);
+                       text.ptr = p;
+                       return;
+               } else
+                       text.size += n;
+       }
+       text.nibuf += n;
+       do {
+               *loc++ = get(&text);
+       } 
+       while (--n);
+}
+
+mput(buf, aloc, an)
+struct buf *buf; 
+int *aloc;
+{
+       register *loc;
+       register n;
+
+       loc = aloc;
+       n = an>>1;
+       do {
+               putw(*loc++, buf);
+       } 
+       while (--n);
+}
+
+dseek(asp, aloc, s)
+long aloc;
+struct stream *asp;
+{
+       register struct stream *sp;
+       register struct page *p;
+       /* register */ long b, o;
+       int n;
+
+       b = aloc >> 8;
+       o = aloc & 0377;
+       sp = asp;
+       --sp->pno->nuser;
+       if ((p = &page[0])->bno!=b && (p = &page[1])->bno!=b)
+               if (p->nuser==0 || (p = &page[0])->nuser==0) {
+                       if (page[0].nuser==0 && page[1].nuser==0)
+                               if (page[0].bno < page[1].bno)
+                                       p = &page[0];
+                       p->bno = b;
+                       lseek(infil, (aloc & ~0377L) << 1, 0);
+                       if ((n = read(infil, (char *)p->buff, 512)>>1) < 0)
+                               n = 0;
+                       p->nibuf = n;
+       } else
+               error(2, "No pages");
+       ++p->nuser;
+       sp->bno = b;
+       sp->pno = p;
+       sp->ptr = p->buff + o;
+       if (s != -1)
+               sp->size = half(s);
+       if ((sp->nibuf = p->nibuf-o) <= 0)
+               sp->size = 0;
+}
+
+half(i)
+{
+       return((i>>1)&077777);
+}
+
+get(asp)
+struct stream *asp;
+{
+       register struct stream *sp;
+
+       sp = asp;
+       if (--sp->nibuf < 0) {
+               dseek(sp, (long)(sp->bno + 1) << 8, -1);
+               --sp->nibuf;
+       }
+       if (--sp->size <= 0) {
+               if (sp->size < 0)
+                       error(2, premeof);
+               ++fpage.nuser;
+               --sp->pno->nuser;
+               sp->pno = (struct page *)&fpage;
+       }
+       return(*sp->ptr++);
+}
+
+getfile(acp)
+char *acp;
+{
+       register char *cp;
+       register int c;
+       struct stat x;
+
+       cp = acp; 
+       infil = -1;
+       archdr.aname[0] = '\0';
+       filname = cp;
+       if (cp[0]=='-' && cp[1]=='l') {
+               if(cp[2] == '\0')
+                       cp = "-la";
+               filname = "/usr/lib/libxxxxxxxxxxxxxxx";
+               for(c=0; cp[c+2]; c++)
+                       filname[c+12] = cp[c+2];
+               filname[c+12] = '.';
+               filname[c+13] = 'a';
+               filname[c+14] = '\0';
+               if ((infil = open(filname+4, 0)) >= 0) {
+                       filname += 4;
+               }
+       }
+       if (infil == -1 && (infil = open(filname, 0)) < 0)
+               error(2, "cannot open");
+       page[0].bno = page[1].bno = -1;
+       page[0].nuser = page[1].nuser = 0;
+       text.pno = reloc.pno = (struct page *)&fpage;
+       fpage.nuser = 2;
+       dseek(&text, 0L, 2);
+       if (text.size <= 0)
+               error(2, premeof);
+       if(get(&text) != ARCMAGIC)
+               return(0);      /* regualr file */
+       dseek(&text, 1L, sizeof archdr);        /* word addressing */
+       if(text.size <= 0)
+               return(1);      /* regular archive */
+       mget((int *)&archdr, sizeof archdr);
+       if(strncmp(archdr.aname, goodnm, 14) != 0)
+               return(1);      /* regular archive */
+       else {
+               fstat(infil, &x);
+               if(x.st_mtime > archdr.atime)
+               {
+                       return(3);
+               }
+               else return(2);
+       }
+}
+
+struct symbol **lookup()
+{
+       int i; 
+       int clash;
+       register struct symbol **hp;
+       register char *cp, *cp1;
+
+       i = 0;
+       for (cp = cursym.sname; cp < &cursym.sname[8];)
+               i = (i<<1) + *cp++;
+       for (hp = &hshtab[(i&077777)%NSYM+2]; *hp!=0;) {
+               cp1 = (*hp)->sname; 
+               clash=FALSE;
+               for (cp = cursym.sname; cp < &cursym.sname[8];)
+                       if (*cp++ != *cp1++) {
+                               clash=TRUE; 
+                               break;
+                       }
+               if (clash) {
+                       if (++hp >= &hshtab[NSYM+2])
+                               hp = hshtab;
+               } else
+                       break;
+       }
+       return(hp);
+}
+
+struct symbol **slookup(s)
+char *s;
+{
+       cp8c(s, cursym.sname);
+       cursym.stype = EXTERN+UNDEF;
+       cursym.svalue = 0;
+       return(lookup());
+}
+
+enter(hp)
+struct symbol **hp;
+{
+       register struct symbol *sp;
+
+       if (*hp==0) {
+               if (symindex>=NSYM)
+                       error(2, "Symbol table overflow");
+               symhash[symindex] = hp;
+               *hp = lastsym = sp = &symtab[symindex++];
+               cp8c(cursym.sname, sp->sname);
+               sp->stype = cursym.stype;
+               sp->svalue = cursym.svalue;
+               return(1);
+       } else {
+               lastsym = *hp;
+               return(0);
+       }
+}
+
+symreloc()
+{
+       switch (cursym.stype) {
+
+       case TEXT:
+       case EXTERN+TEXT:
+               cursym.svalue += ctrel;
+               return;
+
+       case DATA:
+       case EXTERN+DATA:
+               cursym.svalue += cdrel;
+               return;
+
+       case BSS:
+       case EXTERN+BSS:
+               cursym.svalue += cbrel;
+               return;
+
+       case EXTERN+UNDEF:
+               return;
+       }
+       if (cursym.stype&EXTERN)
+               cursym.stype = EXTERN+ABS;
+}
+
+error(n, s)
+char *s;
+{
+       if (errlev==0)
+               printf("ld:");
+       if (filname) {
+               printf("%s", filname);
+               if (archdr.aname[0])
+                       printf("(%.14s)", archdr.aname);
+               printf(": ");
+       }
+       printf("%s\n", s);
+       if (n > 1)
+               delexit();
+       errlev = n;
+}
+
+struct symbol *
+lookloc(alp, r)
+struct local *alp;
+{
+       register struct local *clp, *lp;
+       register sn;
+
+       lp = alp;
+       sn = (r>>4) & 07777;
+       for (clp = local; clp<lp; clp++)
+               if (clp->locindex == sn)
+                       return(clp->locsymbol);
+       error(2, "Local symbol botch");
+}
+
+readhdr(loc)
+long loc;
+{
+       register st, sd;
+
+       dseek(&text, loc, sizeof filhdr);
+       mget((int *)&filhdr, sizeof filhdr);
+       if (filhdr.fmagic != FMAGIC)
+               error(2, "Bad format");
+       st = (filhdr.tsize+01) & ~01;
+       filhdr.tsize = st;
+       cdrel = -st;
+       sd = (filhdr.dsize+01) & ~01;
+       cbrel = - (st+sd);
+       filhdr.bsize = (filhdr.bsize+01) & ~01;
+}
+
+cp8c(from, to)
+char *from, *to;
+{
+       register char *f, *t, *te;
+
+       f = from;
+       t = to;
+       te = t+8;
+       while ((*t++ = *f++) && t<te);
+       while (t<te)
+               *t++ = 0;
+}
+
+eq(s1, s2)
+char *s1; 
+char *s2;
+{
+       while (*s1==*s2++)
+               if ((*s1++)==0)
+                       return(TRUE);
+       return(FALSE);
+}
+
+putw(w, b)
+register struct buf *b;
+{
+       *(b->xnext)++ = w;
+       if (--b->nleft <= 0)
+               flush(b);
+}
+
+flush(b)
+register struct buf *b;
+{
+       register n;
+
+       if ((n = (char *)b->xnext - (char *)b->iobuf) > 0)
+               if (write(b->fildes, (char *)b->iobuf, n) != n)
+                       error(2, "output error");
+       b->xnext = b->iobuf;
+       b->nleft = sizeof(b->iobuf)/sizeof(int);
+}