home *** CD-ROM | disk | FTP | other *** search
- #
- /*
- * link editor
- */
-
- #define SIGINT 2
- #define ARCMAGIC 0177555
- #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 RELFLG 01
- #define NROUT 256
- #define NSYM 501
- #define NSYMPR 500
-
- #define RONLY 0400
-
- char premeof[] "Premature EOF on %s";
-
- 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 archdr {
- char aname[8];
- int atime[2];
- char auid, amode;
- int asize;
- } archdr;
-
- struct filhdr {
- int fmagic;
- int tsize;
- int dsize;
- int bsize;
- int ssize;
- int entry;
- int pad;
- int relflg;
- } filhdr;
-
- struct liblist {
- int off;
- int bno;
- };
-
- struct liblist liblist[NROUT];
- struct liblist *libp { &liblist[0] };
-
- struct symbol {
- char sname[8];
- char stype;
- char spad;
- int svalue;
- };
-
- struct symbol cursym;
- struct symbol symtab[NSYM];
- struct symbol *hshtab[NSYM+2];
- struct symbol *symp { symtab };
- struct symbol **local[NSYMPR];
- struct symbol *p_etext;
- struct symbol *p_edata;
- struct symbol *p_end;
-
- int xflag; /* discard local symbols */
- int Xflag; /* discard locals starting with 'L' */
- 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 dflag; /* define common even with rflag */
- int iflag; /* I/D space separated */
-
- int infil;
- char *filname;
-
- int tsize;
- int dsize;
- int bsize;
- int ssize;
- int nsym;
-
- int torigin;
- int dorigin;
- int borigin;
-
- int ctrel;
- int cdrel;
- int cbrel;
-
- int errlev;
- int delarg 4;
- char tfname[] "/tmp/lxyyyyy";
- int toutb[259];
- int doutb[259];
- int troutb[259];
- int droutb[259];
- int soutb[259];
-
- struct symbol **lookup();
- struct symbol **slookup();
-
- main(argc, argv)
- char **argv;
- {
- extern int delexit();
- register c;
- register char *ap, **p;
- struct symbol **hp;
-
- if ((signal(SIGINT, 1) & 01) == 0)
- signal(SIGINT, delexit);
- if (argc == 1)
- exit(4);
- p = argv + 1;
- for (c = 1; c<argc; c++) {
- filname = 0;
- ap = *p++;
- if (*ap == '-') switch (ap[1]) {
-
- case 'u':
- if (++c >= argc)
- error(1, "Bad 'use'");
- if (*(hp = slookup(*p++)) == 0) {
- *hp = symp;
- enter();
- }
- continue;
-
- case 'l':
- break;
-
- case 'x':
- xflag++;
- continue;
-
- case 'X':
- Xflag++;
- continue;
-
- case 'r':
- rflag++;
- arflag++;
- continue;
-
- case 's':
- sflag++;
- xflag++;
- continue;
-
- case 'n':
- nflag++;
- continue;
-
- case 'd':
- dflag++;
- continue;
-
- case 'i':
- iflag++;
- continue;
- }
- load1arg(ap);
- close(infil);
- }
- middle();
- setupout();
- p = argv+1;
- libp = liblist;
- for (c=1; c<argc; c++) {
- ap = *p++;
- if (*ap == '-') switch (ap[1]) {
-
- case 'u':
- ++c;
- ++p;
- default:
- continue;
-
- case 'l':
- break;
- }
- load2arg(ap);
- close(infil);
- }
- finishout();
- }
-
- load1arg(acp)
- char *acp;
- {
- register char *cp;
- register noff, nbno;
-
- cp = acp;
- if (getfile(cp)==0) {
- load1(0, 0, 0);
- return;
- }
- nbno = 0;
- noff = 1;
- for (;;) {
- dseek(&text, nbno, noff, sizeof archdr);
- if (text.size <= 0) {
- libp->bno = -1;
- libp++;
- return;
- }
- mget(&archdr, sizeof archdr);
- if (load1(1, nbno, noff + (sizeof archdr) / 2)) {
- libp->bno = nbno;
- libp->off = noff;
- libp++;
- }
- noff =+ (archdr.asize + sizeof archdr)>>1;
- nbno =+ (noff >> 8) & 0377;
- noff =& 0377;
- }
- }
-
- load1(libflg, bno, off)
- {
- register struct symbol *sp, **hp, ***cp;
- struct symbol *ssymp;
- int ndef, nloc;
-
- readhdr(bno, off);
- ctrel = tsize;
- cdrel =+ dsize;
- cbrel =+ bsize;
- ndef = 0;
- nloc = sizeof cursym;
- cp = local;
- ssymp = symp;
- if ((filhdr.relflg&RELFLG)==1) {
- error(0, "No relocation bits");
- return(0);
- }
- off =+ (sizeof filhdr)/2 + filhdr.tsize + filhdr.dsize;
- dseek(&text, bno, off, filhdr.ssize);
- while (text.size > 0) {
- mget(&cursym, sizeof cursym);
- if ((cursym.stype&EXTERN)==0) {
- if (Xflag==0 || cursym.sname[0]!='L')
- nloc =+ sizeof cursym;
- continue;
- }
- symreloc();
- hp = lookup();
- if ((sp = *hp) == 0) {
- *hp = enter();
- *cp++ = hp;
- continue;
- }
- if (sp->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.tsize;
- dsize =+ filhdr.dsize;
- bsize =+ filhdr.bsize;
- ssize =+ nloc;
- return(1);
- }
- /*
- * No symbols defined by this library member.
- * Rip out the hash table entries and reset the symbol table.
- */
- symp = ssymp;
- while (cp > local)
- **--cp = 0;
- return(0);
- }
-
- middle()
- {
- register struct symbol *sp;
- register t, csize;
- int nund, corigin;
-
- p_etext = *slookup("_etext");
- p_edata = *slookup("_edata");
- p_end = *slookup("_end");
- /*
- * If there are any undefined symbols, save the relocation bits.
- */
- 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;
- nflag = 0;
- iflag = 0;
- sflag = 0;
- break;
- }
- /*
- * Assign common locations.
- */
- csize = 0;
- if (dflag || rflag==0) {
- 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 =+ t;
- }
- if (p_etext && p_etext->stype==EXTERN+UNDEF) {
- p_etext->stype = EXTERN+TEXT;
- p_etext->svalue = tsize;
- }
- if (p_edata && p_edata->stype==EXTERN+UNDEF) {
- p_edata->stype = EXTERN+DATA;
- p_edata->svalue = dsize;
- }
- if (p_end && p_end->stype==EXTERN+UNDEF) {
- p_end->stype = EXTERN+BSS;
- p_end->svalue = bsize;
- }
- }
- /*
- * 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 =+ csize;
- nsym = ssize / (sizeof cursym);
- }
-
- setupout()
- {
- register char *p;
- register pid;
-
- if ((toutb[0] = creat("l.out", 0666)) < 0)
- error(1, "Can't create l.out");
- pid = getpid();
- for (p = &tfname[12]; p > &tfname[7];) {
- *--p = (pid&07) + '0';
- pid =>> 3;
- }
- tcreat(doutb, 'a');
- if (sflag==0 || xflag==0)
- tcreat(soutb, 'b');
- if (rflag) {
- tcreat(troutb, 'c');
- tcreat(droutb, 'd');
- }
- filhdr.fmagic = FMAGIC;
- if (nflag)
- filhdr.fmagic = NMAGIC;
- if (iflag)
- filhdr.fmagic = IMAGIC;
- filhdr.tsize = tsize;
- filhdr.dsize = dsize;
- filhdr.bsize = bsize;
- filhdr.ssize = sflag? 0: (ssize + (sizeof cursym)*(symp-symtab));
- filhdr.entry = 0;
- filhdr.pad = 0;
- filhdr.relflg = (rflag==0);
- mput(toutb, &filhdr, sizeof filhdr);
- return;
- }
-
- tcreat(buf, letter)
- int *buf;
- {
- tfname[6] = letter;
- if ((buf[0] = creat(tfname, RONLY)) < 0)
- error(1, "Can't create temp");
- }
-
- 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(0, 0);
- return;
- }
- for (lp = libp; lp->bno != -1; lp++) {
- dseek(&text, lp->bno, lp->off, sizeof archdr);
- mget(&archdr, sizeof archdr);
- mkfsym(archdr.aname);
- load2(lp->bno, lp->off + (sizeof archdr) / 2);
- }
- libp = ++lp;
- }
-
- load2(bno, off)
- {
- register struct symbol *sp;
- register int *lp, symno;
-
- readhdr(bno, off);
- ctrel = torigin;
- cdrel =+ dorigin;
- cbrel =+ borigin;
- /*
- * Reread the symbol table, recording the numbering
- * of symbols for fixing external references.
- */
- lp = local;
- symno = -1;
- off =+ (sizeof filhdr)/2;
- dseek(&text, bno, off+filhdr.tsize+filhdr.dsize, filhdr.ssize);
- while (text.size > 0) {
- symno++;
- mget(&cursym, sizeof cursym);
- symreloc();
- if ((cursym.stype&EXTERN) == 0) {
- if (!sflag&&!xflag&&(!Xflag||cursym.sname[0]!='L'))
- mput(soutb, &cursym, sizeof cursym);
- 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++ = symno;
- *lp++ = sp;
- continue;
- }
- if (cursym.stype!=sp->stype || cursym.svalue!=sp->svalue) {
- printf("%.8s: ", cursym.sname);
- error(0, "Multiply defined");
- }
- }
- dseek(&text, bno, off, filhdr.tsize);
- dseek(&reloc, bno, off+(filhdr.tsize+filhdr.dsize)/2, filhdr.tsize);
- load2td(lp, ctrel, toutb, troutb);
- dseek(&text, bno, off+(filhdr.tsize/2), filhdr.dsize);
- dseek(&reloc, bno, off+filhdr.tsize+(filhdr.dsize/2), filhdr.dsize);
- load2td(lp, cdrel, doutb, droutb);
- torigin =+ filhdr.tsize;
- dorigin =+ filhdr.dsize;
- borigin =+ filhdr.bsize;
- }
-
- load2td(lp, creloc, b1, b2)
- int *lp;
- {
- register r, t;
- register struct symbol *sp;
-
- for (;;) {
- /*
- * The pickup code is copied from "get" for speed.
- */
- 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++;
- if (--reloc.size <= 0) {
- if (reloc.size < 0)
- error(1, "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, 'a');
- if (rflag) {
- copy(troutb, 'c');
- copy(droutb, 'd');
- }
- if (sflag==0) {
- if (xflag==0)
- copy(soutb, 'b');
- for (p=symtab; p < symp;)
- putw(*p++, toutb);
- }
- fflush(toutb);
- close(toutb[0]);
- unlink("a.out");
- link("l.out", "a.out");
- delarg = errlev;
- delexit();
- }
-
- delexit()
- {
- register c;
-
- unlink("l.out");
- for (c = 'a'; c <= 'd'; c++) {
- tfname[6] = c;
- unlink(tfname);
- }
- if (delarg==0)
- chmod("a.out", 0777);
- exit(delarg);
- }
-
- copy(buf, c)
- int *buf;
- {
- register f, *p, n;
-
- fflush(buf);
- close(buf[0]);
- tfname[6] = c;
- f = open(tfname, 0);
- while ((n = read(f, doutb, 512)) > 1) {
- n =>> 1;
- p = doutb;
- 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, &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)
- int *aloc;
- {
- register *loc;
- register n;
-
- loc = aloc;
- n = an>>1;
- do {
- putw(*loc++, buf);
- } while (--n);
- }
-
- dseek(asp, ab, o, s)
- {
- register struct stream *sp;
- register struct page *p;
- register b;
- int n;
-
- sp = asp;
- b = ab + ((o>>8) & 0377);
- o =& 0377;
- --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;
- seek(infil, b, 3);
- if ((n = read(infil, p->buff, 512)>>1) < 0)
- n = 0;
- p->nibuf = n;
- } else
- error(1, "No pages");
- ++p->nuser;
- sp->bno = b;
- sp->pno = p;
- sp->ptr = p->buff + o;
- if (s != -1)
- sp->size = (s>>1) & 077777;
- if ((sp->nibuf = p->nibuf-o) <= 0)
- sp->size = 0;
- }
-
- get(asp)
- struct stream *asp;
- {
- register struct stream *sp;
-
- sp = asp;
- if (--sp->nibuf < 0) {
- dseek(sp, sp->bno+1, 0, -1);
- --sp->nibuf;
- }
- if (--sp->size <= 0) {
- if (sp->size < 0)
- error(1, premeof);
- ++fpage.nuser;
- --sp->pno->nuser;
- sp->pno = &fpage;
- }
- return(*sp->ptr++);
- }
-
- getfile(acp)
- char *acp;
- {
- register char *cp;
- register c;
-
- cp = acp;
- archdr.aname[0] = '\0';
- if (cp[0]=='-' && cp[1]=='l') {
- if ((c = cp[2]) == '\0')
- c = 'a';
- cp = "/lib/lib?.a";
- cp[8] = c;
- }
- filname = cp;
- if ((infil = open(cp, 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, 0, 0, 2);
- if (text.size <= 0)
- error(1, premeof);
- return(get(&text) == ARCMAGIC);
- }
-
- struct symbol **lookup()
- {
- int i;
- 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;
- for (cp=cursym.sname; cp < &cursym.sname[8];)
- if (*cp++ != *cp1++)
- goto no;
- break;
- no:
- if (++hp >= &hshtab[NSYM+2])
- hp = hshtab;
- }
- return(hp);
- }
-
- struct symbol **slookup(s)
- char *s;
- {
- cp8c(s, cursym.sname);
- cursym.stype = EXTERN+UNDEF;
- cursym.svalue = 0;
- return(lookup());
- }
-
- enter()
- {
- register struct symbol *sp;
-
- if ((sp=symp) >= &symtab[NSYM])
- error(1, "Symbol table overflow");
- cp8c(cursym.sname, sp->sname);
- sp->stype = cursym.stype;
- sp->svalue = cursym.svalue;
- symp++;
- return(sp);
- }
-
- 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 (filname) {
- printf("%s", filname);
- if (archdr.aname[0])
- printf("(%.8s)", archdr.aname);
- printf(": ");
- }
- printf("%s\n", s);
- if (n)
- delexit();
- errlev = 2;
- }
-
- lookloc(alp, r)
- {
- register int *clp, *lp;
- register sn;
-
- lp = alp;
- sn = (r>>4) & 07777;
- for (clp=local; clp<lp; clp =+ 2)
- if (clp[0] == sn)
- return(clp[1]);
- error(1, "Local symbol botch");
- }
-
- readhdr(bno, off)
- {
- register st, sd;
-
- dseek(&text, bno, off, sizeof filhdr);
- mget(&filhdr, sizeof filhdr);
- if (filhdr.fmagic != FMAGIC)
- error(1, "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;
- }
-