Bell 32V development
authorTom London <tbl@research.uucp>
Wed, 21 Mar 1979 11:13:20 +0000 (06:13 -0500)
committerTom London <tbl@research.uucp>
Wed, 21 Mar 1979 11:13:20 +0000 (06:13 -0500)
Work on file usr/src/cmd/ld.c

Co-Authored-By: John Reiser <jfr@research.uucp>
Synthesized-from: 32v

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..fec3bd8
--- /dev/null
@@ -0,0 +1,1376 @@
+#
+char LD[] = "@(#)ld.c 1.10 78/12/07 15:34:58"; /* sccs ident */
+/*
+ *  link editor for VAX
+ */
+
+/*     layout of a.out file:
+ *
+ *     header of 8 words       magic number 0410:
+                                       data starts at 1st 0777
+                                       boundary above text
+                               magic number 0407:
+                                       data starts immediately after
+                                       text
+ *                             text size       )
+ *                             data size       ) in bytes
+ *                             bss size        )
+ *                             symbol table size
+ *                             entry point
+ *                             size of text relocation info
+ *                             size of data relocation info
+ *
+ *  'segment'   origin   comments
+ *     header:         0
+ *     text:           32       0 padded to multiple of 4 bytes
+ *     data:           32+textsize     0 padded to multiple of 4 bytes
+ *     text relocation:        32+textsize+datasize
+ *     data relocation:        32+textsize+datasize+textrelocationsize
+ *     symbol table:   32+textsize+datasize+textrelocationsize+datarelocationsize
+ *
+ */
+#include <signal.h>
+#include <stdio.h>
+#include <ar.h>
+#include <a.out.h>
+
+struct {short hiword; short loword;}; /* stupid fp-11 */
+fixl(p) register long *p;{
+       register short t;
+       t=p->hiword; p->hiword=p->loword; p->loword=t;
+}
+
+writel(p,n,f) long *p; FILE *f; {
+#ifdef vax
+       fwrite(p,sizeof(*p),n,f);
+#else
+       while (n--) {
+               fwrite(&(*p).loword,2,1,f);
+               fwrite(&(*p).hiword,2,1,f);
+               p++;
+       }
+#endif
+}
+
+long htoi(p) register char *p; {/* hex to integer conversion */
+register long n = 0;
+while (*p) {
+       n <<= 4;
+       if              (*p<='9' && *p>='0') n += *p - '0';
+       else if (*p<='f' && *p>='a') n += *p -'a' +10;
+       else if (*p<='F' && *p>='A') n += *p -'A' +10;
+       p++;
+}
+return(n);
+}
+
+typedef        char *STRING;
+typedef        int BOOL;
+#define TRUE   1
+#define FALSE  0
+
+#define        OMAGIC  0407
+#define        NMAGIC  0410
+
+/*
+ * Symbol types
+ */
+#define        UNDEF   0x0
+#define        ABS     0x2
+#define        TEXT    0x4
+#define        DATA    0x6
+#define        BSS     0x8
+#define        DATAO   0xA
+#define        BSSO    0xC
+#define        TEXTO   0xE
+#define        ABSO    0x10
+
+#define        COMM    0x12    /* for internal use only */
+
+#define        EXTERN  0x1
+#define        TYPE    0x1E
+#define STABTYPS 0xE0
+/*
+ * address reference types
+ */
+#define PCREL  1
+#define LEN1   0
+#define LEN2   2
+#define LEN4   4
+
+#define        HW      01
+#define        FW      03
+#define        DW      07
+
+#define        PAGRND  0777
+
+#define        TYPMASK 0x1E
+#define        TYMASK  (0x1E)
+#define TMASK  0x1F
+
+#define        RABS    (ABS)
+#define        RTEXT   TEXT
+#define        RDATA   DATA
+#define        RBSS    BSS
+#define        RDATAO  DATAO
+#define        RBSSO   BSSO
+#define        RTEXTO  TEXTO
+#define        RABSO   ABSO
+#define        REXT    (01<<3)
+#define        ROFF    (02<<3)
+#define        REFMASK 0x7
+
+#define NOVLY  1
+#define        RELFLG  01
+#define        NROUT   256
+#define        NSYM    1103
+#define        NSYMPR  500
+
+char   premeof[] = "Premature EOF";
+
+typedef struct {
+       long    loc;
+} LIBLIST;
+
+/* overlay management */
+int    vindex;
+typedef struct {
+       int     argsav;
+       int     symsav;
+       LIBLIST *libsav;
+       STRING  vname;
+       long    ctsav, cdsav, cbsav;
+       long    offt, offd, offb, offtr, offdr, offs;
+} OVERLAY;
+OVERLAY        vnodes[NOVLY];
+
+/* input management */
+typedef struct {
+       short   *fakeptr;
+       int     bno;
+       int     nibuf;
+       int     nuser;
+       char    buff[512];
+} PAGE;
+
+PAGE   page[2];
+
+struct {
+       short   *fakeptr;
+       int     bno;
+       int     nibuf;
+       int     nuser;
+} fpage;
+
+typedef struct {
+       char    *ptr;
+       int     bno;
+       int     nibuf;
+       long    size;
+       long    pos;
+       PAGE    *pno;
+} STREAM;
+
+STREAM text;
+STREAM reloc;
+
+struct ar_hdr archdr;
+
+struct exec filhdr;
+
+/* one entry for each archive member referenced;
+ * set in first pass; needs restoring for overlays
+ */
+
+LIBLIST        liblist[NROUT];
+LIBLIST        *libp = liblist;
+
+
+/* symbol management */
+typedef struct {
+       char    sname[8];
+       char    stype;
+       char    spare;
+       short   symhash;        /* index of hash table entry pointing to this symbol */
+       long    svalue;
+} SYMBOL;
+
+typedef struct {
+       int locindex;           /* index to symbol in file */
+       SYMBOL *locsymbol;      /* ptr to symbol table */
+} LOCAL;
+
+SYMBOL cursym;                 /* current symbol */
+SYMBOL *symtab;                /* actual symbols */
+SYMBOL *lastsym;               /* last symbol entered */
+SYMBOL *nextsym;               /* next available symbol table entry */
+int nsym;                      /* number of symbols allocated in symtab */
+SYMBOL *hshtab[NSYM+2];        /* hash table for symbols */
+LOCAL  *local;
+
+/* internal symbols */
+SYMBOL *p_data;
+SYMBOL *p_etext;
+SYMBOL *p_edata;
+SYMBOL *p_end;
+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 = 1;      /* pure procedure */
+int    dflag;          /* define common even with rflag */
+int    iflag;          /* I/D space separated */
+BOOL   vflag;          /* overlays used */
+
+int    ofilfnd;
+char   *ofilename      = "l.out";
+int    infil;
+char   *filname;
+
+long   textbase;
+/* cumulative sizes set in pass 1 */
+long   tsize;
+long   dsize;
+long   bsize;
+long   trsize;
+long   drsize;
+long   ssize;
+
+/* symbol relocation; both passes */
+long   ctrel;
+long   cdrel;
+long   cbrel;
+long   ctorel;
+long   cdorel;
+long   cborel;
+
+int    errlev;
+int    delarg  = 4;
+
+
+FILE   *tout;
+FILE   *dout;
+char   *doutn  = "";
+FILE   *trout;
+char   *troutn = "";
+FILE   *drout;
+char   *droutn = "";
+FILE   *sout;
+char   *soutn  = "";
+
+char   *mktemp();
+char   get();
+char   getb();
+short  gets();
+long   get3();
+long   getl();
+SYMBOL **lookup();
+FILE   *tcreat();
+long   round();
+SYMBOL **slookup();
+SYMBOL *lookloc();
+
+symwrite(sp,n,f) SYMBOL *sp; FILE *f; {
+#ifdef vax
+       fwrite(sp,sizeof(*symtab),n,f);
+#else
+       while (n--) {
+               fwrite(sp,sizeof(*symtab)-sizeof(sp->svalue),1,f);
+               writel(&(sp->svalue),1,f); sp++;
+       }
+#endif
+}
+
+delexit()
+{
+       unlink("l.out");
+       unlink(doutn);
+       unlink(troutn);
+       unlink(droutn);
+       unlink(soutn);
+       if (delarg==0)
+               chmod(ofilename, 0777);
+       exit(delarg);
+}
+
+main(argc, argv)
+char **argv;
+{
+       register int c, i; 
+       int num;
+       register char *ap, **p;
+       BOOL found; 
+       int vscan; 
+       char save;
+
+       if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+               signal(SIGINT, delexit);
+       if (argc == 1)
+               exit(4);
+       p = argv+1;
+
+       nextsym=symtab=sbrk(0); nsym=0;
+       /* 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(1, "Bad output file");
+                               ofilename = *p++;
+                               ofilfnd++;
+                               continue;
+
+                       case 'u':
+                       case 'e':
+                               if (++c >= argc)
+                                       error(1, "Bad 'use' or 'entry'");
+                               enter(slookup(*p++));
+                               if (ap[i]=='e')
+                                       entrypt = lastsym;
+                               continue;
+
+                       case 'v':
+                               if (++c >= argc)
+                                       error(1, "-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(1, "-D: arg missing");
+                               num = htoi(*p++);
+                               if (dsize>num)
+                                       error(1, "-D: too small");
+                               dsize = num;
+                               continue;
+
+                       case 'T':
+                               if (++c >= argc)
+                                       error(1, "-T: arg missing");
+                               if (tsize!=0)
+                                       error(1, "-T: too late, some text already loaded");
+                               textbase = htoi(*p++);
+                               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 'N':
+                               nflag = 0;
+                               continue;
+
+                       case 'd':
+                               dflag++;
+                               continue;
+
+                       case 'i':
+                               iflag++;
+                               continue;
+
+                       case 't':
+                               trace++;
+                               continue;
+
+                       default:
+                               error(1, "bad flag");
+                       } /*endsw*/
+                       break;
+                       } /*endfor*/
+               } else
+                       load1arg(ap);
+       }
+       endload(argc, argv);
+       exit(0);
+}
+
+/* used after pass 1 */
+long   torigin;
+long   dorigin;
+long   borigin;
+long   database;
+
+endload(argc, argv)
+int argc; 
+char **argv;
+{
+       register int c, i; 
+       long dnum;
+       register char *ap, **p;
+
+       brk(nextsym);
+       filname = 0;
+       middle();
+       setupout();
+       if (-1==(local=sbrk(NSYMPR*sizeof(*local)))) error(1,"Memory overflow");
+       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 = htoi(*p); dorigin<dnum; dorigin++) putc(0, dout);
+                       case 'T':
+                       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; 
+STRING nam;
+{
+       register OVERLAY *v;
+
+       v = &vnodes[vindex++];
+       v->argsav = c;
+       v->symsav = nextsym-symtab;
+       v->libsav = libp;
+       v->vname = nam;
+       v->offt = tsize; 
+       v->offd = dsize; 
+       v->offb = bsize; 
+       v->offtr = trsize;
+       v->offdr = drsize;
+       v->offs = ssize;
+       v->ctsav = ctrel; 
+       v->cdsav = cdrel; 
+       v->cbsav = cbrel;
+}
+
+restore(vscan)
+int vscan;
+{
+       register OVERLAY *v;
+       register SYMBOL *saved,*sp;
+
+       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; 
+       trsize = v->offtr;
+       drsize = v->offdr;
+       ssize = v->offs;
+       saved = symtab + v->symsav;
+       sp = nextsym;
+       while (sp>saved)
+               hshtab[(--sp)->symhash]=0;
+       nextsym = saved;
+}
+
+/* scan file to find defined symbols */
+load1arg(cp)
+register char *cp;
+{
+       long loc;
+
+       if (getfile(cp)==0)
+               load1(0, 0L);
+       else {
+               loc = sizeof(int);
+               for (;;) {
+                       dseek(&text, loc, (long)sizeof(archdr));
+                       if (text.size <= 0) {
+                               libp->loc = -1;
+                               libp++;
+                               return;
+                       }
+                       mget((short *)&archdr, sizeof archdr, &text);
+                       if (load1(1, loc+sizeof(archdr))) {
+                               libp->loc = loc;
+                               libp++;
+                       }
+#ifndef vax
+                       if (archdr.ar_size.loword==0) fixl(&archdr.ar_size);
+#endif
+                       loc += round(archdr.ar_size, 1) + sizeof(archdr);
+               }
+       }
+       close(infil);
+}
+
+/* single file or archive member */
+load1(libflg, loc)
+long loc;
+{
+       register SYMBOL *sp;
+       SYMBOL *savnext;
+       int ndef, nlocal, type;
+
+       readhdr(loc);
+       ctrel = tsize;
+       cdrel += dsize;
+       cbrel += bsize;
+       ndef = 0;
+       nlocal = sizeof(cursym);
+       savnext = nextsym;
+/*     if (filhdr.a_trsize+filhdr.a_drsize==0) {
+/*             error(0, "No relocation bits");
+/*             return(0);
+/*     }
+*/
+       loc += filhdr.a_text + filhdr.a_data +
+                       filhdr.a_trsize + filhdr.a_drsize + sizeof(filhdr);
+       dseek(&text, loc, filhdr.a_syms);
+       while (text.size > 0) {
+               symget(&cursym, &text);
+               type = cursym.stype;
+               if ((type&EXTERN)==0) {
+                       if (Xflag==0 || cursym.sname[0]!='L' || type&STABTYPS)
+                               nlocal += 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 += filhdr.a_text;
+               dsize += round(filhdr.a_data, FW);
+               bsize += round(filhdr.a_bss, FW);
+               ssize += nlocal;
+               trsize += filhdr.a_trsize;
+               drsize += filhdr.a_drsize;
+               return(1);
+       }
+       /*
+        * No symbols defined by this library member.
+        * Rip out the hash table entries and reset the symbol table.
+        */
+       while (nextsym>savnext)
+               hshtab[(--nextsym)->symhash]=0;
+       return(0);
+}
+
+middle()
+{
+       register SYMBOL *sp, *symp;
+       long csize, t, corigin, ocsize;
+       int nund, rnd;
+       char s;
+
+       torigin = 0; 
+       dorigin = 0; 
+       borigin = 0;
+
+       p_data = *slookup("_data");
+       p_etext = *slookup("_etext");
+       p_edata = *slookup("_edata");
+       p_end = *slookup("_end");
+       /*
+        * If there are any undefined symbols, save the relocation bits.
+        */
+       symp = nextsym;
+       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
+                               && sp!=p_data) {
+                               rflag++;
+                               dflag = 0;
+                               break;
+                       }
+       }
+       if (rflag) 
+               sflag = iflag = 0;
+       /*
+        * Assign common locations.
+        */
+       csize = 0;
+       database = round(tsize+textbase, (nflag? PAGRND:FW));
+       if (dflag || rflag==0) {
+               ldrsym(p_data, (long)0 , EXTERN+DATA);
+               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 ((s=sp->stype)==EXTERN+UNDEF && (t = sp->svalue)!=0) {
+                               if (t>DW)
+                                       rnd = DW;
+                               else if (t>FW)
+                                       rnd = FW;
+                               else
+                                       rnd = HW;
+                               csize = round(csize, rnd);
+                               sp->svalue = csize;
+                               sp->stype = EXTERN+COMM;
+                               ocsize = csize; 
+                               csize += t;
+                       }
+                       if (((s&TMASK) == EXTERN+UNDEF) && (s & STABTYPS)) {
+                               sp->svalue = ocsize;
+                               sp->stype = (s & STABTYPS) | (EXTERN+COMM);
+                       }
+               }
+       }
+       /*
+        * Now set symbols to their final value
+        */
+       csize = round(csize, FW);
+       torigin = textbase;
+       dorigin = database;
+       corigin = dorigin + dsize;
+       borigin = corigin + csize;
+       cdorel = 0;
+       cborel = dsize+csize;
+       nund = 0;
+       for (sp = symtab; sp<symp; sp++) switch (sp->stype & TMASK) {
+       case EXTERN+UNDEF:
+               errlev |= 01;
+               if ((arflag==0 || dflag) && 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 = (sp->stype & STABTYPS) | (EXTERN+BSS);
+               sp->svalue += corigin;
+               continue;
+       }
+       if (sflag || xflag)
+               ssize = 0;
+       bsize += csize;
+       nsym = ssize / (sizeof cursym);
+}
+
+ldrsym(asp, val, type)
+long val;
+SYMBOL *asp;
+{
+       register SYMBOL *sp;
+
+       if ((sp = asp) == 0)
+               return;
+       if (sp->stype != EXTERN+UNDEF || sp->svalue) {
+               printf("%.8s: ", sp->sname);
+               error(0, "Multiply defined (internal)");
+               return;
+       }
+       sp->stype = type;
+       sp->svalue = val;
+}
+
+extern char _sibuf[BUFSIZ]; /* the space is forced upon us; might as well use it */
+
+setupout()
+{
+       tout = fopen(ofilename, "w");
+       if (tout==NULL)
+               error(1, "cannot create output");
+       setbuf(tout,_sibuf);
+       dout = tcreat(&doutn, "/tmp/ldaaXXXXX");
+       if (sflag==0 || xflag==0)
+               sout = tcreat(&soutn, "/tmp/ldbaXXXXX");
+       if (rflag) {
+               trout = tcreat(&troutn, "/tmp/ldcaXXXXX");
+               drout = tcreat(&droutn, "/tmp/lddaXXXXX");
+       }
+       filhdr.a_magic = nflag? NMAGIC:OMAGIC;
+       filhdr.a_text = nflag? tsize:round(tsize, FW);
+       filhdr.a_data = dsize;
+       filhdr.a_bss = bsize;
+       filhdr.a_trsize = trsize;
+       filhdr.a_drsize = drsize;
+       filhdr.a_syms = sflag? 0: (ssize + (sizeof cursym)*(nextsym-symtab));
+       if (entrypt) {
+               if (entrypt->stype!=EXTERN+TEXT)
+                       error(0, "Entry point not in text");
+               else
+                       filhdr.a_entry = entrypt->svalue;
+       } else
+               filhdr.a_entry=0;
+       filhdr.a_trsize = (rflag ? trsize:0);
+       filhdr.a_drsize = (rflag ? drsize:0);
+       writel(&filhdr,8,tout);
+}
+
+FILE *
+tcreat(namep, name)
+char **namep, *name;
+{
+       register FILE *fp;
+       register char *tnm;
+
+       tnm = mktemp(name);
+       if ((fp = fopen(tnm, "w")) == NULL)
+               error(1, "Cannot create temp file");
+       chmod(tnm, 0600);
+       *namep = tnm;
+       return(fp);
+}
+
+load2arg(acp)
+char *acp;
+{
+       register char *cp;
+       register 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, (long)sizeof(archdr));
+                       mget((short *)&archdr, sizeof(archdr), &text);
+                       mkfsym(archdr.ar_name);
+                       load2(lp->loc + (long)sizeof(archdr));
+               }
+               libp = ++lp;
+       }
+       close(infil);
+}
+
+load2(loc)
+long loc;
+{
+       register SYMBOL *sp;
+       register LOCAL *lp;
+       register int symno;
+       int type;
+
+       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);
+       dseek(&text, loc+filhdr.a_text+filhdr.a_data+
+               filhdr.a_trsize+filhdr.a_drsize, filhdr.a_syms);
+       while (text.size > 0) {
+               symno++;
+               symget(&cursym, &text);
+               symreloc();
+               type = cursym.stype;
+               if ((type&EXTERN) == 0) {
+                       if (!sflag&&!xflag&&(!Xflag||cursym.sname[0]!='L'||type&STABTYPS))
+                               symwrite(&cursym, 1, sout);
+                       continue;
+               }
+               if ((sp = *lookup()) == 0)
+                       error(1, "internal error: symbol not found");
+               if (cursym.stype == EXTERN+UNDEF) {
+                       if (lp >= local+NSYMPR)
+                               error(1, "Local symbol overflow");
+                       lp->locindex = symno;
+                       lp++->locsymbol = sp;
+                       continue;
+               }
+               if(cursym.stype & STABTYPS) continue;
+               if (cursym.stype!=sp->stype || cursym.svalue!=sp->svalue) {
+                       printf("%.8s: ", cursym.sname);
+                       error(0, "Multiply defined");
+               }
+       }
+       dseek(&text, loc, filhdr.a_text);
+       dseek(&reloc, loc+filhdr.a_text+filhdr.a_data, filhdr.a_trsize);
+       load2td(lp, ctrel, 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);
+       load2td(lp, cdrel, dout, drout);
+       while (filhdr.a_data&FW) {
+               putc(0, dout); filhdr.a_data++;
+       }
+       torigin += filhdr.a_text;
+       dorigin += filhdr.a_data;
+       borigin += filhdr.a_bss;
+       cdorel += filhdr.a_data;
+       cborel += filhdr.a_bss;
+}
+
+load2td(lp, creloc, b1, b2)
+LOCAL *lp;
+long creloc;
+FILE *b1, *b2;
+{
+       register r1;
+       register char r2; 
+       register long t;
+       register SYMBOL *sp;
+       long tw,u,l;
+
+       for (;;) {
+       if (reloc.size==0) {while (text.size) putc(get(&text),b1); break;}
+       t=getl(&reloc); /* position of relocatable stuff */
+       if (rflag) putl(t+creloc,b2); /* remember for subsequent link editing */
+       while (text.pos<t) putc(get(&text),b1); /* advance to proper position */
+       r1=get3(&reloc); /* kind of relocation */
+       r2 = getb(&reloc);
+       switch (r2&06) {/* read raw datum according to its length */
+               case LEN1: tw=get(&text); break;
+               case LEN2: tw=gets(&text); break;
+               case LEN4: tw=getl(&text); break;
+       }
+       if (r2&REXT) {
+               sp=lookloc(lp,r1); /* find the symbol */
+               if (sp->stype==EXTERN+UNDEF) { /* still undefined */
+                       r2=(r2&(REFMASK+REXT+ROFF));
+                       r1 = nsym+(sp-symtab); /* new reloc */
+               }
+               else {
+                       if (sp->stype==EXTERN+DATA && r2&ROFF) {
+                               r1=RDATAO;
+                               r2&=REFMASK;
+                       }
+                       else if (sp->stype==EXTERN+BSS && r2&ROFF) {
+                               r1=RBSSO;
+                               r2&=REFMASK;
+                       }
+                       else if (sp->stype==EXTERN+ABS && r2&ROFF) {
+                               r1=RABSO;
+                               r2&=REFMASK;
+                       }
+                       else if (sp->stype==EXTERN+TEXT && r2&ROFF) {
+                               r1=RTEXTO;
+                               r2&=REFMASK;
+                       }
+                       else {if (r2&ROFF) {if (rflag) {error(0,"!-r; see JFR"); rflag=0;}}
+                                else tw += database;
+                                r1=sp->stype&TYPE;
+                                r2&=REFMASK;
+                       }
+                       tw += sp->svalue - database;
+               }
+       } else switch (r1&TYMASK) {
+               case RTEXT:     tw += ctrel; break;
+               case RTEXTO:tw += round(filhdr.a_text,PAGRND)+ctrel-database; break;
+               case RDATA: tw += cdrel; break;
+               case RDATAO:tw += cdorel; break;
+               case RBSS:      tw += cbrel; break;
+               case RBSSO: tw += cborel-filhdr.a_data; break;
+               case RABSO: tw += round(filhdr.a_text,PAGRND)-database; break;
+       }
+       if (rflag) { /* remember for subsequent link editing */
+               put3(r1,b2);
+               putb(r2,b2);
+       }
+       if (r2&PCREL) tw -= creloc; /* assembler already subtracted text.pos */
+       switch (r2&06) {/* output relocated datum according to its length */
+               case LEN1: l= -128; u=127; putc((char)tw,b1); break;
+               case LEN2: l= -32768; u=32767; puts((short)tw,b1); break;
+               case LEN4: l=0x80000000; u=0x7FFFFFFF; putl(tw,b1); break;
+       }
+       if (tw<l || u<tw) error(0,"Displacement overflow");
+       }
+}
+
+finishout()
+{
+
+       if (!nflag)
+               while (tsize&FW) {
+                       putc(0, tout); tsize++;
+               }
+       fclose(dout);
+       copy(doutn);
+       if (rflag) {
+               fclose(trout);
+               copy(troutn);
+               fclose(drout);
+               copy(droutn);
+       }
+       if (sflag==0) {
+               if (xflag==0) {
+                       fclose(sout);
+                       copy(soutn);
+               }
+               symwrite(symtab, nextsym-symtab, tout);
+       }
+       fclose(tout);
+       if (!ofilfnd) {
+               unlink("a.out");
+               link("l.out", "a.out");
+               ofilename = "a.out";
+       }
+       delarg = errlev;
+       delexit();
+}
+
+copy(np)
+char *np;
+{
+       register c;
+       register FILE *fp;
+
+       if ((fp = fopen(np, "r")) == NULL)
+               error(1, "cannot recopy output");
+       while ((c = getc(fp)) != EOF)
+               putc(c, tout);
+       fclose(fp);
+}
+
+mkfsym(s)
+char *s;
+{
+
+       if (sflag || xflag)
+               return;
+       cp8c(s, cursym.sname);
+       cursym.stype = TEXT;
+       cursym.svalue = torigin;
+       symwrite(&cursym, 1, sout);
+}
+
+mget(loc, n, sp)
+register STREAM *sp;
+register char *loc;
+{
+       register char *p;
+
+       if ((sp->nibuf -= n) >= 0) {
+               if ((sp->size -= n) > 0) {
+                       p = sp->ptr;
+                       sp->pos += n;
+                       do
+                               *loc++ = *p++;
+                       while (--n);
+                       sp->ptr = p;
+                       return;
+               } else
+                       sp->size += n;
+       }
+       sp->nibuf += n;
+       do {
+               *loc++ = get(sp);
+       } while (--n);
+}
+
+short
+gets(sp) STREAM *sp; {
+short t; mget(&t,2,sp); return(t);
+}
+
+char
+getb(sp) STREAM *sp; {
+char t; mget(&t,1,sp); return(t);
+}
+
+long
+get3(sp) STREAM *sp; {
+long t; t=0; mget(&t,3,sp); return(t);
+}
+
+long
+getl(sp) STREAM *sp; {
+       long t; mget(&t,4,sp);
+#ifndef vax
+       fixl(&t);
+#endif
+       return(t);
+}
+
+symget(sp,f) SYMBOL *sp; STREAM *f; {
+       mget(sp,sizeof(*sp),f);
+#ifndef vax
+       fixl(&sp->svalue);
+#endif
+}
+
+dseek(sp, loc, s)
+register STREAM *sp;
+long loc, s;
+{
+       register PAGE *p;
+       register b, o;
+       int n;
+
+       b = loc>>9;
+       o = loc&0777;
+       if (o&01)
+               error(1, "loader error; odd offset");
+       --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, loc & ~0777L, 0);
+                       if ((n = read(infil, p->buff, sizeof(p->buff))) < 0)
+                               n = 0;
+                       p->nibuf = n;
+       } else
+               error(1, "No pages");
+       ++p->nuser;
+       sp->bno = b;
+       sp->pno = p;
+       if (s != -1) {sp->size = s; sp->pos = 0;}
+       sp->ptr = (short *)(p->buff + o);
+       if ((sp->nibuf = p->nibuf-o) <= 0)
+               sp->size = 0;
+}
+
+char
+get(asp)
+STREAM *asp;
+{
+       register STREAM *sp;
+
+       sp = asp;
+       if ((sp->nibuf -= sizeof(char)) < 0) {
+               dseek(sp, ((long)(sp->bno+1)<<9), (long)-1);
+               sp->nibuf -= sizeof(char);
+       }
+       if ((sp->size -= sizeof(char)) <= 0) {
+               if (sp->size < 0)
+                       error(1, premeof);
+               ++fpage.nuser;
+               --sp->pno->nuser;
+               sp->pno = &fpage;
+       }
+       sp->pos += sizeof(char);
+       return(*sp->ptr++);
+}
+
+getfile(acp)
+STRING acp;
+{
+       register STRING cp;
+       register int c;
+       int arcmag;
+
+       cp = acp; 
+       infil = -1;
+       archdr.ar_name[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(1, "cannot open");
+       page[0].bno = page[1].bno = -1;
+       page[0].nuser = page[1].nuser = 0;
+       text.pno = reloc.pno = &fpage;
+       fpage.nuser = 2;
+       dseek(&text, 0L, (long)sizeof(int));
+       if (text.size <= 0)
+               error(1, premeof);
+       mget(&arcmag, sizeof(arcmag), &text);
+       return(arcmag==ARMAG);
+}
+
+SYMBOL **lookup()
+{
+       int i; 
+       BOOL clash;
+       register 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);
+}
+
+SYMBOL **slookup(s)
+char *s;
+{
+       cp8c(s, cursym.sname);
+       cursym.stype = EXTERN+UNDEF;
+       cursym.svalue = 0;
+       return(lookup());
+}
+
+enter(hp)
+register SYMBOL **hp;
+{
+       register SYMBOL *sp;
+
+       if (*hp==0) {
+               if ((nextsym-symtab)>=NSYM)
+                       error(1, "Symbol table overflow");
+               if ((nextsym-symtab)>=nsym) {
+                       if (-1==sbrk(NSYM/5 * sizeof(*symtab))) error(1,"Memory overflow");
+                       nsym += NSYM/5;
+               }
+               *hp = lastsym = sp = nextsym++;
+               cp8c(cursym.sname, sp->sname);
+               sp->stype = cursym.stype;
+               sp->symhash = hp-hshtab;
+               sp->svalue = cursym.svalue;
+               return(1);
+       } else {
+               lastsym = *hp;
+               return(0);
+       }
+}
+
+symreloc()
+{
+       switch (cursym.stype & 017) {
+
+       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.ar_name[0])
+                       printf("(%.14s)", archdr.ar_name);
+               printf(": ");
+       }
+       printf("%s\n", s);
+       if (n)
+               delexit();
+       errlev = 2;
+}
+
+SYMBOL *
+lookloc(lp, r)
+register LOCAL *lp;
+{
+       register LOCAL *clp;
+       register sn;
+
+       sn = r;
+       for (clp = local; clp<lp; clp++)
+               if (clp->locindex == sn)
+                       return(clp->locsymbol);
+       error(1, "Local symbol botch");
+}
+
+readhdr(loc)
+long loc;
+{
+       long *p; int i;
+       dseek(&text, loc, (long)sizeof(filhdr));
+       mget((short *)&filhdr, sizeof(filhdr), &text);
+#ifndef vax
+       for (p= &filhdr,i=8;--i>=0;) fixl(p++);
+#endif
+       if (filhdr.a_magic!=A_MAGIC1 && filhdr.a_magic!=A_MAGIC2 &&
+               filhdr.a_magic!=A_MAGIC3 && filhdr.a_magic!=A_MAGIC4)
+                       error(1,"Bad magic number");
+       if (filhdr.a_text&01 || filhdr.a_data&01) {
+               printf("tsize=%X  dsize=%X\n",filhdr.a_text,filhdr.a_data);
+               error(1, "Text/data size odd");
+       }
+       filhdr.a_bss = round(filhdr.a_bss, FW);
+       if (filhdr.a_magic == NMAGIC) {
+               cdrel = -round(filhdr.a_text, PAGRND);
+               cbrel = cdrel - filhdr.a_data;
+       } else if (filhdr.a_magic == OMAGIC) {
+               cdrel = -filhdr.a_text;
+               cbrel = cdrel - filhdr.a_data;
+       } else
+               error(1, "Bad format");
+}
+
+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)
+STRING s1; 
+STRING s2;
+{
+       while (*s1==*s2++)
+               if ((*s1++)==0)
+                       return(TRUE);
+       return(FALSE);
+}
+
+long
+round(v, r)
+long v;
+unsigned r;
+{
+       v += r;
+       v &= ~(long)r;
+       return(v);
+}
+
+puts(w, f)
+FILE *f; short w; {
+fwrite(&w,sizeof(short),1,f);
+}
+
+putb(w, f)
+FILE *f; char w; {
+fwrite(&w,sizeof(char),1,f);
+}
+
+put3(w, f)
+FILE *f; long w; {
+fwrite(&w,3,1,f);
+}
+
+putl(w, f)
+FILE *f; long w; {
+#ifndef vax
+       fixl(&w);
+#endif
+       fwrite(&w,sizeof(long),1,f);
+}