V7/usr/src/cmd/ld.c
/*
* 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);
}