|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 11185 (0x2bb1)
Types: TextFile
Notes: UNIX file
Names: »pass1.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/ld/pass1.c«
/*
* Pass 1:
* Read input file
* If not archive, add it to module list
* If archive, add all modules that satisfy global references
* iterating until no more can be satisfied
* If it is not a ranlib, this must be done the hard way
*/
char nospace[] = "out of space";
int
rdfile(fname)
char *fname;
{
size_t offs, arhend;
arh_t arh;
struct stat arstat;
int magic, found;
FILE *ifp;
if ((ifp=fopen(fname, "r"))==NULL)
return (0);
fstat(fileno(ifp), &arstat);
if (fread(&magic, sizeof magic, 1, ifp)!=1)
fatal("can't read %s", fname);
canshort(magic);
if (magic!=ARMAG) {
rewind(ifp);
addmod(ifp, (size_t)0, fname, "");
} else if (fread(&arh, sizeof arh, 1, ifp)==1) {
cantime(arh.ar_date);
cansize(arh.ar_size);
arhend = sizeof magic+sizeof arh+arh.ar_size;
if (strncmp(arh.ar_name, HDRNAME, DIRSIZ)!=0) {
arhend = sizeof magic; /* not ranlib */
} else if (arstat.st_mtime > arh.ar_date+SLOPTIME) {
filemsg(fname, "outdated ranlib");
} else {
FILE *xfp = fopen(fname, "r");
ars_t ars;
if (watch)
filemsg(fname, "ranlib");
do {
found = 0;
fseek(xfp, offs=sizeof magic+sizeof arh, 0);
for (; offs < arhend; offs+=sizeof ars) {
if (fread(&ars, sizeof ars, 1, xfp)!=1)
break;
if (symref(&ars)==NULL)
continue;
cansize(ars.ar_off);
fseek(ifp, ars.ar_off+=arhend, 0);
if (fread(&arh, sizeof arh, 1, ifp)!=1)
break;
found |= addmod(ifp,
ars.ar_off+=sizeof arh,
fname, arh.ar_name);
}
} while (nundef&&found);
fclose(xfp);
fclose(ifp);
return (1);
}
do {
found = 0;
fseek(ifp, offs=arhend, 0);
while (offs < arstat.st_size) {
if (fread(&arh, sizeof arh, 1, ifp)!=1)
break;
cansize(arh.ar_size);
offs += sizeof arh;
found |= modref(ifp, offs, fname, arh.ar_name);
fseek(ifp, offs+=arh.ar_size, 0);
}
} while (nundef&&found);
}
fclose(ifp);
return (1);
}
/*
* Check whether module satisfies any global references.
* If so, add the module to the list and return flag indicating success
*/
int
modref(fp, offs, fname, mname)
FILE *fp;
size_t offs;
char *fname, mname[];
{
ldh_t ldh;
lds_t lds;
unsigned int nsym;
if (fread(&ldh, sizeof ldh, 1, fp)!=1) {
modmsg(fname, mname, "can't read");
return (0);
}
canldh(&ldh);
if (ldh.l_magic!=L_MAGIC) {
modmsg(fname, mname, "bad header");
return (0);
}
if ((ldh.l_flag & LF_32) == 0) {
modmsg(fname, mname, "not a 32-bit l.out");
return (0);
}
fseek(fp, symoff(&ldh), 1);
for (nsym=ldh.l_ssize[L_SYM]/sizeof lds; nsym; nsym--) {
if (fread(&lds, sizeof lds, 1, fp)!=1) {
modmsg(fname, mname, "bad symbol segment");
return (0);
}
canshort(lds.ls_type);
if (lds.ls_type&L_GLOBAL
&& lds.ls_type!=(L_GLOBAL|L_REF)
&& symref(&lds)!=NULL) {
fseek(fp, offs, 0);
return (addmod(fp, offs, fname, mname));
}
}
return (0);
}
/*
* Allocate module descriptor and add to end of list.
*/
int
addmod(fp, offs, fname, mname)
FILE *fp;
size_t offs;
char *fname, mname[];
{
mod_t *mp;
ldh_t ldh;
lds_t lds;
int i, segn;
unsigned int nsym;
size_t max;
if (watch)
modmsg(fname, mname, "adding");
if (fread(&ldh, sizeof ldh, 1, fp)!=1) {
modmsg(fname, mname, "can't read");
return (0);
}
canldh(&ldh);
if (ldh.l_magic!=L_MAGIC) {
modmsg(fname, mname, "bad header");
return (0);
}
if ((ldh.l_flag & LF_32) == 0) {
modmsg(fname, mname, "not 32-bit load module");
return (0);
}
if ((ldh.l_flag & LF_SLIB) != 0) {
oldh.l_flag |= LF_SLREF;
if (watch)
modmsg(fname, mname, "shared library adding");
rdsymbol(fname);
return (0);
}
if (ldh.l_flag&LF_SEP) {
modmsg(fname, mname, "cannot load separated I/D");
return (0);
}
if (oldh.l_machine==0) {
machine = ldh.l_machine;
switch (oldh.l_machine = machine) {
case M_PDP11:
case M_8086:
worder = LOHI;
lorder = HILO;
break;
case M_Z8001:
segoff++;
case M_68000:
case M_Z8002:
worder = HILO;
lorder = HILO;
break;
default:
modmsg(fname, mname, "can't load %s code (yet)",
mchname[machine]);
exit(1);
}
} else if (ldh.l_machine!=machine) {
modmsg(fname, mname, "inconsistent machine");
return (0);
}
if (lmodel)
lfixup1(&ldh);
/*
* allocate descriptor, add to list, initialize
*/
nsym = ldh.l_ssize[L_SYM]/sizeof(lds_t);
if ((mp=malloc(sizeof(mod_t)+nsym*sizeof(sym_t *)))==NULL)
fatal(nospace);
if (modhead==NULL)
modhead = mp;
else
modtail->next = mp;
modtail = mp;
mp->next = NULL;
mp->fname = fname;
for (i=0; i<DIRSIZ; i++)
mp->mname[i] = mname[0] ? mname[i] : 0;
for (i=0; i<NLSEG; i++)
mp->seg[i].size = ldh.l_ssize[i];
baseall(mp->seg, &ldh);
segoffs(mp->seg, offs);
mp->nsym = nsym;
/*
* add symbols
*/
fseek(fp, symoff(&ldh), 1);
for (i=0; i < nsym; i++) {
if (fread(&lds, sizeof lds, 1, fp)!=1) {
modmsg(fname, mname, "bad symbol segment");
mp->nsym = i;
break;
} else {
canshort(lds.ls_type);
canlong(lds.ls_addr);
segn = lds.ls_type&~L_GLOBAL;
if (segn<L_SYM) /* make symbols segment relative */
lds.ls_addr += oseg[segn].size
- mp->seg[segn].vbase;
mp->sym[i] = addsym(&lds, mp);
}
}
max = segmax[machine];
for (i=0; i<NLSEG; i++)
if (i!=L_SYM)
oseg[i].size += ldh.l_ssize[i];
if (lmodel)
baseall(oseg, &oldh);
return (1);
}
/*
* Do any fixup to next segment here
* for large model.
*/
void
lfixup1(ldhp)
register ldh_t *ldhp;
{
char *calloc();
register int i;
register mod_t *mp;
extern char *sname[];
static uaddr_t max1, max;
uaddr_t d;
max = segmax[machine];
max1 = max-1;
for (i=0; i<NXSEG; i++) {
d = oseg[i].size & max1;
if (d + ldhp->l_ssize[i] <= max)
continue;
d = max-d;
printf("adding module of %D bytes in %s\n", d, sname[i]);
if ((mp = (mod_t*)calloc(sizeof(*mp))) == NULL)
fatal(nospace);
if (modhead == NULL) /* Can't happen ? */
modhead = mp; else
modtail->next = mp;
modtail = mp;
mp->next = NULL;
mp->fname = NULL;
mp->nsym = 0;
mp->seg[i].size = d;
mp->seg[i].vbase = 0;
oseg[i].size += d;
}
}
/*
* Add symbol to symbol table
* If match, resolve references and definitions
* otherwise, create new symbol entry.
* Keep track of number of undefined symbols,
* amount of space required by commons,
* size of output symbol segment.
*/
sym_t *
addsym(lsp, mp)
register lds_t *lsp;
mod_t *mp;
{
register sym_t *sp;
int h;
h = hash(lsp->ls_id);
if (!(lsp->ls_type&L_GLOBAL)) {
if (nolcl || noilcl && lsp->ls_id[0] == 'L')
return (NULL);
} else for (sp=symtable[h]; sp!=NULL; sp=sp->next) {
if (sp->s.ls_type&L_GLOBAL && eq(sp->s.ls_id, lsp->ls_id)) {
if (lsp->ls_type!=(L_GLOBAL|L_REF)) {
if (sp->s.ls_type!=(L_GLOBAL|L_REF))
/* new def, old def */
symredef(sp, mp);
else if (sp->s.ls_addr == 0
|| commdef(sp->mod, mp, lsp)) {
/* new def, old ref */
/* common compatible with def */
if (sp->s.ls_addr == 0)
nundef--;
sp->s.ls_type = lsp->ls_type;
sp->s.ls_addr = lsp->ls_addr;
sp->mod = mp;
}
} else if (sp->s.ls_type!=(L_GLOBAL|L_REF)) {
/* new ref, old def */
if (lsp->ls_addr!=0)
commdef(mp, sp->mod, &sp->s);
} else if (sp->s.ls_addr < lsp->ls_addr) {
/* new ref > old ref */
if (sp->s.ls_addr==0) /* ref becomes comm */
nundef--;
commons += lsp->ls_addr - sp->s.ls_addr;
sp->s.ls_addr = lsp->ls_addr;
sp->mod = mp;
}
return (sp);
}
}
/*
* symbol not found (or is local)
*/
if ((sp=malloc(sizeof(sym_t)))==NULL)
fatal("out of space");
oseg[L_SYM].size += sizeof(lds_t);
sp->next = symtable[h];
symtable[h] = sp;
sp->s = *lsp; /* struct assign */
sp->mod = mp;
/*
* note reference to internal symbol
*/
if (eq(sp->s.ls_id, etext_id))
etext_s = sp;
else if (eq(sp->s.ls_id, edata_id))
edata_s = sp;
else if (eq(sp->s.ls_id, end_id))
end_s = sp;
else if (sp->s.ls_type==(L_GLOBAL|L_REF))
if (sp->s.ls_addr==0)
nundef++;
else
commons += (uaddr_t)sp->s.ls_addr;
return (sp);
}
/*
* complain about redefined symbol
*/
void
symredef(sp, mp)
sym_t *sp;
mod_t *mp;
{
if (mp->mname[0]=='\0')
spmsg(sp, "redefined in file %s", mp->fname);
else
spmsg(sp, "redefined in file %s: module %.*s",
mp->fname, DIRSIZ, mp->mname);
}
/*
* Check if common compatible with symbol definition
*/
int
commdef(cmp, dmp, lsp)
mod_t *cmp, *dmp;
lds_t *lsp;
{
int type = lsp->ls_type&~L_GLOBAL;
if (type!=L_PRVI && type!=L_SHRI)
return (1);
if (dmp->mname[0]==0)
mpmsg(cmp, "common %.*s: conflicts with code in file %s",
NCPLN, lsp->ls_id, dmp->fname);
else
mpmsg(cmp, "common %.*s: conflicts with code in file %s: module %.*s",
NCPLN, lsp->ls_id, dmp->fname, DIRSIZ, dmp->mname);
return (0);
}
/*
* Add symbols from object file to
* the general symbol table as absolutes.
*/
void
rdsymbol(modnam)
char *modnam;
{
FILE *fp;
ldh_t ldh;
lds_t lds;
sym_t *sp;
int i;
if ((fp=fopen(modnam, "r"))==NULL)
fatal("can't open %s", modnam);
if (fread(&ldh, sizeof ldh, 1, fp)!=1)
return; /* allow null input file */
canldh(&ldh);
if (ldh.l_magic!=L_MAGIC) {
filemsg(modnam, "bad header");
return;
}
if ((ldh.l_flag & LF_32) == 0) {
filemsg(modnam, "not 32-bit load module");
return;
}
if (ldh.l_machine != machine) {
filemsg(modnam, "inconsistent machine");
return;
}
fseek(fp, symoff(&ldh), 1);
for (i=ldh.l_ssize[L_SYM]/sizeof lds; i; i--) {
if (fread((char *)&lds, sizeof lds, 1, fp) != 1) {
filemsg(modnam, "bad symbol segment");
return;
} else {
canshort(lds.ls_type);
canlong(lds.ls_addr);
if (lds.ls_type&L_GLOBAL
&& lds.ls_type!=(L_GLOBAL|L_REF)
&& (sp=symref(&lds))!=NULL) {
sp->s.ls_type = L_GLOBAL | L_ABS;
sp->s.ls_addr = vtop(lds.ls_addr);
nundef--;
}
}
}
}
/*
* Return reference to given symbol if any
*/
sym_t *
symref(ldsp)
union {lds_t; ars_t;} *ldsp;
{
register sym_t *sp;
for (sp=symtable[hash(ldsp->ls_id)]; sp!=NULL; sp=sp->next)
if (sp->s.ls_type==(L_GLOBAL|L_REF)
&& sp->s.ls_addr == 0
&& eq(sp->s.ls_id, ldsp->ls_id))
break;
return (sp);
}
/*
* Compute hash index into symbol table by summing chars in name
* (mod table length)
*/
int
hash(id)
char id[];
{
register char *s = &id[0];
register int h, i;
for (h=i=0; *s && i<NCPLN; i++)
h += *s++;
return (h%NHASH);
}
/*
* Compare two symbol names
*/
int
eq(id, jd)
char id[], jd[];
{
register char *si = &id[0], *sj = &jd[0];
register int i;
for (i=0; *si && *sj && i<NCPLN; i++)
if (*si++ != *sj++)
return (0);
return (*si==*sj);
}
/*
* Calculate file offset of symbol segment relative to end of header
*/
size_t
symoff(ldhp)
register ldh_t *ldhp;
{
register size_t offs;
register int i;
offs = ldhp->l_tbase - sizeof(*ldhp);
for (i=0; i<L_SYM; i++)
if (i==L_BSSI || i==L_BSSD)
continue;
else
offs += ldhp->l_ssize[i];
return (offs);
}
void
canldh(ldhp)
register ldh_t *ldhp;
{
register size_t *sp, *ep;
canshort(ldhp->l_magic);
canshort(ldhp->l_flag);
canshort(ldhp->l_machine);
canshort(ldhp->l_tbase);
sp = &ldhp->l_ssize[0];
ep = &ldhp->l_ssize[NLSEG];
while (sp < ep) {
canlong(*sp);
sp++;
}
}