DataMuseum.dk

Presents historical artifacts from the history of:

Commodore CBM-900

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Commodore CBM-900

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦6b34adcd2⟧ TextFile

    Length: 11185 (0x2bb1)
    Types: TextFile
    Notes: UNIX file
    Names: »pass1.c«

Derivation

└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
    └─⟦f4b8d8c84⟧ UNIX V7 Filesystem
        └─ ⟦this⟧ »cmd/ld/pass1.c« 

TextFile

/*
 * 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++;
	}
}