BSD 3 development
[unix-history] / usr / src / cmd / ld.c
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 (PAGSIZ)
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>
#include <pagsiz.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 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[BSIZE];
} 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 zflag;
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 &~ umask(0));
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;
case 'z':
zflag++;
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;
if( ++libp >= liblist + NROUT)
error(1,"liblist overflow");
/* thanks to Dennis Wasley */
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;
/*
if (zflag)
borigin = round(borigin, PAGRND);
*/
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()
{
int bss;
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;
if (zflag)
filhdr.a_magic = nflag?0413:0412;
filhdr.a_text = nflag? tsize:round(tsize, FW);
if (zflag)
filhdr.a_text = round(tsize, PAGRND);
filhdr.a_data = dsize;
if (zflag)
filhdr.a_data = round(dsize, PAGRND);
bss = bsize - (filhdr.a_data - dsize);
if (bss < 0)
bss = 0;
filhdr.a_bss = bss;
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);
if (zflag)
fseek(tout, PAGSIZ, 0);
}
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++;
}
if (zflag) {
while (tsize&PAGRND) {
putc(0, tout); tsize++;
}
while (dsize&PAGRND) {
putc(0, dout); dsize++;
}
}
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>>BSHIFT;
o = loc&BMASK;
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 & ~(long)BMASK, 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)<<BSHIFT), (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') {
char *locfilname = "/usr/local/lib/libxxxxxxxxxxxxxxx";
if(cp[2] == '\0')
cp = "-la";
filname = "/usr/lib/libxxxxxxxxxxxxxxx";
for(c=0; cp[c+2]; c++) {
filname[c+12] = cp[c+2];
locfilname[c+18] = cp[c+2];
}
filname[c+12] = locfilname[c+18] = '.';
filname[c+13] = locfilname[c+19] = 'a';
filname[c+14] = locfilname[c+20] = '\0';
if ((infil = open(filname+4, 0)) >= 0) {
filname += 4;
} else if ((infil = open(filname, 0)) < 0) {
filname = locfilname;
}
}
if (infil == -1 && (infil = open(filname, 0)) < 0)
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);
}