File:  [MW Coherent from dump] / coherent / b / bin / c / n2 / i386 / outcoh.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:37 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * n2/i386/outcoh.c
 * The routines in this file make up
 * a writer for the Coherent style l.out object
 * file. During code assembly all the bits get
 * written to a temporary file. At the very end the
 * bits get copied back to the final object file.
 * This uses the newest compiler base (the one
 * that does "readonly" and has the segment names rearranged).
 * i386.
 */

#ifdef   vax
#include "INC$LIB:cc2.h"
#include "INC$LIB:canon.h"
#include "INC$LIB:lout.h"
#else
#include "cc2.h"
#include "canon.h"
#include "l.out.h"
#endif

#define	NTXT	256			/* Text buffer size */
#define	NREL	256			/* Relocation buffer size */

/*
 * Scratch file.
 */
#define	TTYPE	07			/* Type */
#define	TTYPE	07			/* Type */
#define	TPCR	010			/* PC rel flag, ored in */
#define	TSYM	020			/* Symbol based flag, ored in */
#define	T8087	0340			/* 8087 flags */

#define	TEND	00			/* End marker */
#define	TENTER	01			/* Enter new area */
#define	TBYTE	02			/* Byte data */
#define	TWORD	03			/* Word data */
#define	TCODE	04			/* Code segment base */
#define	TDATA	05			/* Data segment base */
#define	TBASE	06			/* External segment base */

#define	TWT	0040			/* M:_WT  */
#define	TWST	0100			/* M:_WST */
#define	TWES	0140			/* M:_WES */
#define	TWCS	0200			/* M:_WCS */
#define	TWSS	0240			/* M:_WSS */
#define	TWDS	0300			/* M:_WDS */

struct	ldheader ldh;			/* Header buffer */
long	crseek;				/* Current relocation seek address */
ADDRESS	txtla;				/* Load address */
char	txt[NTXT];			/* Text buffer */
char	rel[NREL];			/* Relocation buffer */
char	*txtp;				/* Text pointer */
char	*relp;				/* Relocation pointer */

/*
 * Convert a C compiler segment into
 * an "l.out" segment. This is no longer a
 * one to one mapping.
 */
char	segindex[] = {
	L_SHRI,				/* SCODE */
	L_SHRI,				/* SLINK */
	L_SHRD,				/* SPURE */
	0,				/* SSTRN (Patched) */
	L_PRVD,				/* SDATA */
	L_BSSD				/* SBSS  */
};

/*
 * Output a segment switch.
 */
outseg(s)
{
	bput(TENTER);
	bput(s);
}

/*
 * Output an absolute byte.
 */
outab(b)
{
	bput(TBYTE);
	bput(b);
	++dot;
}

/*
 * Output an absolute word.
 */
outaw(w)
{
	bput(TWORD);
	iput((ival_t)w);
	dot += 2;
}

/*
 * Output a full byte.
 */
outxb(sp, b, pcrf)
register SYM	*sp;
{
	register int	opcode;

	opcode = TBYTE;
	if (sp != NULL)
		opcode |= TSYM;
	if (pcrf)
		opcode |= TPCR;
	bput(opcode);
	bput(b);
	if (sp != NULL)
		pput(sp);
	++dot;
}

/*
 * Output a full word.
 */
outxw(sp, w, pcrf)
register SYM	*sp;
{
	register int	opcode;

	opcode = TWORD;
	if (sp != NULL)
		opcode |= TSYM;
	if (pcrf)
		opcode |= TPCR;
	bput(opcode);
	iput((ival_t)w);
	if (sp != NULL)
		pput(sp);
	dot += 2;
}

/*
 * Output a 1 word object containing
 * the base address of the current code
 * segment.
 */
outcb()
{
	bput(TCODE);
	dot += 2;
}

/*
 * Output a 1 word object containing
 * the base address of the current data
 * segment.
 */
outdb()
{
	bput(TDATA);
	dot += 2;
}

/*
 * Output a 1 word object containing
 * the base address of the external symbol
 * pointed to by 'sp'.
 */
outsb(sp)
SYM	*sp;
{
	bput(TBASE);
	pput(sp);
	dot += 2;
}

/*
 * Copy a dlabel record from ifp to nowhere.
 */
outdlab(i, n)
int i;		/* Indentation */
register int n;	/* Class initially */
{
	/* Get line number */
	iget();

	/* Get value */
	if (n < DC_AUTO)
		;
	else if (n < DC_MOS)
		iget();
	else {
		bget();		/* Width */
		bget();		/* Offset */
		iget();		/* Value */
	}

	/* Get name */
	sget(id, NCSYMB);

	/* Get type */
	for (;;) {
		n = bget();
		if (n < DC_SEX) {
			if (n < DX_MEMBS)
				iget();
			if (n == DX_MEMBS) {
				++i;
				n = iget();
				for ( ; n > 0; n-=1) {
					outdlab(i, bget());
				}
				--i;
				break;
			} else if (n == DX_NAME) {
				iget();
				sget(id, NCSYMB);
				break;
			} else if (n < DT_STRUCT)
				break;
		} else
			cbotch("unrecognized type byte: %d", n);
	}

	/* Done */
}

/*
 * Forget a debug line record.
 */
outdlin(op)
{
}

/*
 * Forget a debug relocation record.
 */
outdloc(n)
{
}

/*
 * Initialize the code writer.
 */
outinit()
{
	txtp = &txt[0];
	relp = &rel[0];
}

/*
 * Finish up.
 */
outdone()
{
	if (notvariant(VASM))
		bput(TEND);
}

/*
 * Copy back.
 * Figure out the sizes and final values
 * of everything. Copy the code from the scratch
 * file back to the output file.
 */
copycode()
{
	register SYM	*sp;
	register SEG	*segp;
	register int	op;
	register int	data;
	register ADDRESS mseek;
	register long	dseek;
	register int	nd;
	register int	nr;
	register int	index;
	register ADDRESS segsize;
	register ADDRESS auxsize;
	register ADDRESS reldot;
	register int	refnum;
	register int	i;
	register int	rop;
	struct	 ldsym	lds;

	/*
	 * Make sure that the "segindex"
	 * table is set up correctly for the string
	 * mapping, based on the VPSTR flags.
	 */
	if (isvariant(VPSTR))
		segindex[SSTRN] = L_SHRD;
	else
		segindex[SSTRN] = L_PRVD;
	/*
	 * Sweep through the segment table and
	 * assign the memory and disc seek addresses to each
	 * entry. Two sections (SLINK and SSTRN) are done in
	 * a magic way, because they live in another segment.
	 */
	mseek = 0;
	index = 0;
	dseek = sizeof(ldh);
	for (segp=&seg[SCODE]; segp<=&seg[SBSS]; ++segp) {
		if (segp!=&seg[SLINK] && segp!=&seg[SSTRN]) {
			segp->s_mseek = mseek;
			segsize = rup(segp->s_dot);
			mseek += segsize;
			if (segp != &seg[SBSS]) {
				segp->s_dseek = dseek;
				dseek += segsize;
			}
			if (segp == &seg[SCODE]) {
				seg[SLINK].s_mseek = mseek;
				auxsize = rup(seg[SLINK].s_dot);
				mseek += auxsize;
				seg[SLINK].s_dseek = dseek;
				dseek += auxsize;
				segsize += auxsize;
			}
			if (isvariant(VPSTR) && segp==&seg[SPURE]
			||  notvariant(VPSTR) && segp==&seg[SDATA]) {
				seg[SSTRN].s_mseek = mseek;
				auxsize = rup(seg[SSTRN].s_dot);
				mseek += auxsize;
				seg[SSTRN].s_dseek = dseek;
				dseek += auxsize;
				segsize += auxsize;
			}
			ldh.l_ssize[segindex[index]] = segsize;
		}
		++index;
	}
	/*
	 * Seek to the start of the symbol table and
	 * write out all of the global symbols. All symbols get
	 * relocated to their final values here. Reference numbers
	 * are assigned to every symbol.
	 */
	fseek(ofp, dseek, 0);
	ldh.l_ssize[L_SYM] = 0;
	refnum = 0;
	for (i=0; i<NSHASH; ++i) {
		sp = hash2[i];
		while (sp != NULL) {
			if ((sp->s_flag&S_DEF) != 0)
				sp->s_value += seg[sp->s_seg].s_mseek;
			if ((sp->s_flag&S_GBL)!=0 || (sp->s_flag&S_DEF)==0) {
				sp->s_ref = refnum++;
				ldscopy(lds.ls_id, sp->s_id);
				lds.ls_type = L_REF;
				if ((sp->s_flag&S_DEF) != 0)
					lds.ls_type = segindex[sp->s_seg];
				lds.ls_type |= L_GLOBAL;
				lds.ls_addr = sp->s_value;
				canint(lds.ls_type);
				canvaddr(lds.ls_addr);
				owrite((char *) &lds, sizeof(lds));
				ldh.l_ssize[L_SYM] += sizeof(lds);
			}
			sp = sp->s_fp;
		}
	}
	/*
 	 * Copy out code.
	 */
	crseek = ftell(ofp);
	ldh.l_ssize[L_REL] = 0;
	for (segp=&seg[SCODE]; segp<=&seg[SBSS]; ++segp)
		segp->s_dot = 0;
	dotseg = SCODE;
	dot = 0;
	while ((op = bget()) != TEND) {
		if (op==TCODE || op==TDATA || op==TBASE)
			cbotch("large item");
		if ((op&T8087) != 0)
			cbotch("8087 item");
		if (op == TENTER) {
			notenuf();
			seg[dotseg].s_dot = dot;
			dotseg = bget();
			dot = seg[dotseg].s_dot;
			continue;
		}
		if ((op&TTYPE) == TBYTE) {
			nd = 1;
			data = bget();
		} else {
			nd = 2;
			data = iget();
		}
		if ((op&TPCR) != 0)
			data -= dot+nd;
		/*
		 * Absolute.
		 */
		if ((op&(TSYM|TPCR)) == 0) {
			enuf(nd, 0);
			*txtp++ = data;
			if (nd != 1)
				*txtp++ = data>>8;
			dot += nd;
			continue;
		}
		/*
		 * Not symbol based.
		 * Must be absolute and PC rel.
		 */
		reldot = dot + seg[dotseg].s_mseek;
		if ((op&TSYM) == 0) {
			enuf(nd, 3);
			rop = LR_BYTE|L_ABS|LR_PCR;
			*txtp++ = data;
			if (nd != 1) {
				rop = LR_WORD|L_ABS|LR_PCR;
				*txtp++ = data>>8;
			}
			*relp++ = rop;
			*relp++ = reldot;
			*relp++ = reldot>>8;
			dot += nd;
			continue;
		}
		/*
		 * Symbol based.
		 * Might be PC rel.
	 	 */
		nr = 5;
		sp = pget();
		if ((sp->s_flag&S_DEF) != 0) {
			nr = 3;
			data += sp->s_value;
		}
		enuf(nd, nr);
		rop = LR_BYTE;
		*txtp++ = data;
		if (nd != 1) {
			rop = LR_WORD;
			*txtp++ = data>>8;
		}
		if ((op&TPCR) != 0)
			rop |= LR_PCR;
		if (nr == 3)
			rop |= segindex[sp->s_seg];
		else
			rop |= L_SYM;
		*relp++ = rop;
		*relp++ = reldot;
		*relp++ = reldot>>8;
		if (nr == 5) {
			*relp++ = sp->s_ref;
			*relp++ = sp->s_ref>>8;
		}
		dot += nd;
	}
	/*
	 * Flush buffers.
	 * Write out the l.out header, since we
	 * now know the size of the relocation section.
	 */
	notenuf();
	ldh.l_magic = L_MAGIC;
	canint(ldh.l_magic);
	ldh.l_flag = 0;
	canint(ldh.l_flag);
	ldh.l_machine = M_8086;
	canint(ldh.l_machine);
	ldh.l_entry = 0;
	canvaddr(ldh.l_entry);
	for (i=L_SHRI; i<=L_REL; ++i)
		cansize(ldh.l_ssize[i]);
	fseek(ofp, (long)0, 0);
	owrite((char *) &ldh, sizeof(ldh));
}

/*
 * Copy a NUL terminated name into
 * a loader symbol. Pad the symbol out with
 * 0 bytes.
 */
ldscopy(p1, p2)
register char	*p1;
register char	*p2;
{
	register int	n;

	n = NCPLN;
	while (*p2!=0 && n!=0) {
		*p1++ = *p2++;
		--n;
	}
	while (n != 0) {
		*p1++ = 0;
		--n;
	}
}

/*
 * This routine checks to see if
 * there is enough room in the text and relocation
 * buffers to hold 'nt' bytes of text and 'nr' bytes of
 * relocation.
 */
enuf(nt, nr)
{
	if (txtp+nt>&txt[NTXT] || relp+nr>&rel[NREL])
		notenuf();
	if (txtp == txt)
		txtla = dot;
}

/*
 * Flush the text and relocation buffers. Look
 * at the segment table to figure out the exact location
 * of the data in the file, and compute the correct seek
 * address in the image by adding the base address of
 * the text record "txtla" to that base.
 */
notenuf()
{
	register int	n;

	if ((n=txtp-txt) != 0) {
		fseek(ofp, txtla+seg[dotseg].s_dseek, 0);
		owrite(txt, n);
		if ((n=relp-rel) != 0) {
			fseek(ofp, crseek, 0);
			owrite(rel, n);
			crseek += n;
			ldh.l_ssize[L_REL] += n;
			relp = rel;
		}
	}
	txtp = txt;
}

/*
 * Write a block of bytes to the output file,
 * looking at the return status and checking for any
 * write errors.
 */
owrite(p, n)
char	*p;
{
	if (fwrite(p, sizeof(char), n, ofp) != n)
		cfatal("output write error");
}

/*
 * Round up a size to the next
 * even boundry.
 */
rup(a)
{
	return ((a+01)&~01);
}

/* end of n2/i386/outcoh.c */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.