File:  [MW Coherent from dump] / coherent / b / bin / c / n2 / i386 / outcoff.c.sav
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/outcoff.c
 * C compiler COFF output writer.
 * The first pass writes to a temp file.
 * After the first pass, the compiler knows the sizes of the internal segments.
 * The compiler then maps the internal segments to the actual output segments.
 * The second pass reads the temp file and writes the actual output bits.
 * i386.
 */

#include <stdio.h>
#include <time.h>
#include <string.h>
#include "cc2.h"
#include "coff.h"

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

#define	RUP(n)	(((n)+3)&(~3))		/* Round n up to dword boundary	*/

/* SYM flag tests. */
#define	isbss(sp)	((sp)->s_seg==SBSS)
#define	isdef(sp)	(((sp)->s_flag&S_DEF)!=0)
#define	isglobal(sp)	(((sp)->s_flag&S_GBL)!=0)
#define	islabel(sp)	(((sp)->s_flag&S_LABNO)!=0)

/* Debugging output. */
#if	DEBUG
#define	dbprintf(args)	printf args
#else
#define	dbprintf(args)
#endif

/*
 * COFF output.
 * The structure of the COFF output file is presently as follows:
 *	file header
 *	[optional header: absent]
 *	section headers 1 through n
 *	data for sections 1 through n
 *	relocs for sections 1 through n
 *	[line numbers: absent]
 *	symbol table [segment names, then symbols]
 *	string table
 * These definitions correspond to the header definitions in scn_hdr[] below.
 * These are used as array indices and as indices into COFF symbol table.
 * Add 1 to get the COFF segment number.
 * They will have to change when full debug info is desired.
 */
#define	C_CODE_SEG	0			/* Code segment index	*/
#define	C_DATA_SEG	1			/* Data segment index	*/
#define	C_BSS_SEG	2			/* BSS segment index	*/
#define	C_NSEGS		3			/* Number of segments	*/
#define	C_UNDEF		0			/* Undefined segment	*/

/*
 * Scratch file.
 */
#define	TTYPE	0x07			/* Type				*/
#define	TPCR	0x08			/* PC rel flag, or'ed in	*/
#define	TSYM	0x10			/* Symbol based flag, or'ed in	*/

#define	TEND	0x00			/* End marker			*/
#define	TENTER	0x01			/* Enter new segment		*/
#define	TBYTE	0x02			/* Byte data			*/
#define	TWORD	0x03			/* Word data			*/
#define	TLONG	0x04			/* Dword data			*/

/*
 * Output writer globals.
 */
FILEHDR	coff_hdr;			/* Header buffer	*/
int	coff_seg;			/* Current COFF segment	*/
char	rel[NREL];			/* Relocation buffer	*/
ADDRESS	reldot[C_NSEGS];		/* Relocation offsets	*/
char	*relp;				/* Relocation pointer	*/
SCNHDR	scn_hdr[C_NSEGS] = {		/* Section headers	*/
	{ ".text", 0L, 0L, 0L, 0L, 0L, 0L, 0, 0, STYP_TEXT },
	{ ".data", 0L, 0L, 0L, 0L, 0L, 0L, 0, 0, STYP_DATA },
	{ ".bss",  0L, 0L, 0L, 0L, 0L, 0L, 0, 0, STYP_BSS }
};
char	txt[NTXT];			/* Text buffer		*/
ADDRESS	txtdot;				/* Text offset		*/
char	*txtp;				/* Text pointer		*/

/*
 * Map C compiler internal segment into a COFF output segment.
 * The SSTRN entry gets patched by outinit() if not -VPSTR.
 */
char	segindex[] = {
	C_CODE_SEG,				/* SCODE */
	C_CODE_SEG,				/* SLINK */
	C_CODE_SEG,				/* SPURE */
	C_CODE_SEG,	/* possibly patched */	/* SSTRN */
	C_DATA_SEG,				/* SDATA */
	C_BSS_SEG				/* SBSS  */
};

/* First pass routines. */
/*
 * Initialize the code writer.
 */
outinit()
{
#if	MONOLITHIC
	memset(&coff_hdr, 0, sizeof coff_hdr);
	coff_seg = 0;
	memset(reldot, 0, sizeof reldot);
	memset(scn_hdr, 0, sizeof scn_hdr);
	strcpy(scn_hdr[C_CODE_SEG].s_name, ".text");
	scn_hdr[C_CODE_SEG].s_flags = STYP_TEXT;
	strcpy(scn_hdr[C_DATA_SEG].s_name, ".data");
	scn_hdr[C_DATA_SEG].s_flags = STYP_DATA;
	strcpy(scn_hdr[C_BSS_SEG].s_name, ".bss");
	scn_hdr[C_BSS_SEG].s_flags = STYP_BSS;
#endif
	if (notvariant(VPSTR))
		segindex[SSTRN] = C_DATA_SEG;
}

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

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

/*
 * Output an absolute dword.
 */
outal(i) ival_t i;
{
	bput(TLONG);
	iput(i);
	dot += 4;
}

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

	opcode = TBYTE;
	if (sp != NULL) {
		opcode |= TSYM;
		scn_hdr[coff_seg].s_nreloc++;
	}
	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; ADDRESS w; int pcrf;
{
	register int	opcode;

	opcode = TWORD;
	if (sp != NULL) {
		opcode |= TSYM;
		scn_hdr[coff_seg].s_nreloc++;
	}
	if (pcrf)
		opcode |= TPCR;
	bput(opcode);
	iput((ival_t)w);
	if (sp != NULL)
		pput(sp);
	dot += 2;
}

/*
 * Output a full dword.
 */
outxl(sp, i, pcrf) register SYM *sp; ADDRESS i; int pcrf;
{
	register int	opcode;

	opcode = TLONG;
	if (sp != NULL) {
		opcode |= TSYM;
		scn_hdr[coff_seg].s_nreloc++;
	}
	if (pcrf)
		opcode |= TPCR;
	bput(opcode);
	iput(i);
	if (sp != NULL)
		pput(sp);
	dot += 4;
}

/*
 * Output a segment switch.
 */
outseg(s) register int s;
{
	bput(TENTER);
	bput(s);
	coff_seg = segindex[s];
}

/*
 * Output n zero bytes.
 * If flag is true, generate NOPs instead.
 */
outnzb(n, flag) register sizeof_t n; int flag;
{
	register int i, val;

	val = (flag) ? 0x90 : 0;	/* xchg %eax, %eax or 0 */
	for (i = 1; i <= n; ++i) {
		bput(TBYTE);
		bput(val);
	}
	dot += n;
}

/*
 * 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 relocation record.
 */
outdloc(n) int n;
{
}

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

/* Second pass. */
copycode()
{
	register int op, i;
	register SEG *segp;
	register SYM *sp;
	register long dseek, sseek, ssize;
	register ADDRESS mseek, segsize;
	int symnum, nd, len, isbyte, isword, issym, ispcr;
	ival_t data;
	SCNHDR *shp;
	SYMENT sym;
	RELOC *rp;

	/* Assign segment base addresses. */
	coff_seg = -1;
	dseek = sizeof(FILEHDR) + C_NSEGS * sizeof(SCNHDR);
	mseek = 0;
	for (i = SCODE, segp = &seg[SCODE]; i <= SBSS; ++i, ++segp) {
		segsize = RUP(segp->s_dot);
		segp->s_dot = 0;
		if (segindex[i] != coff_seg) {
			/* Begin new COFF segment. */
			coff_seg = segindex[i];
			dbprintf(("COFF segment %d\n", coff_seg));
			shp = &scn_hdr[coff_seg];
			shp->s_paddr = shp->s_vaddr = mseek;
			if (i != C_BSS_SEG)
				shp->s_scnptr = dseek;
		}
		dbprintf(("segment %d: size=%d dseek=%ld mseek=%ld\n", i, segsize, dseek, mseek));
		segp->s_dseek = dseek;		/* set compiler seg disk seek */
		segp->s_mseek = mseek;		/* and memory seek */
		scn_hdr[coff_seg].s_size += segsize;	/* bump COFF seg size */
		dseek += segsize;		/* bump seek pointer */
		mseek += segsize;		/* bump memory seek */
	}

	/* Fix reloc offsets. */
	for (shp = &scn_hdr[C_CODE_SEG]; shp < &scn_hdr[C_NSEGS]; ++shp) {
		if (shp->s_nreloc != 0) {
			shp->s_relptr = dseek;
			dseek += shp->s_nreloc * sizeof(RELOC);
		}
	}

	/* Write symbols. */
	coff_hdr.f_symptr = dseek;		/* symbol secton base */
	oseek(dseek);				/* seek to symbol section */
	sym.n_type = 0;				/* ignore type */
	sym.n_numaux = 0;			/* no aux entries */
	for (i = C_CODE_SEG, shp = &scn_hdr[i]; i < C_NSEGS; ++i, ++shp) {
		/* Write segment name symbols. */
		memset(sym.n_name, 0, sizeof(sym.n_name));
		strcpy(sym.n_name, shp->s_name);
		sym.n_value = shp->s_vaddr;
		sym.n_scnum = i + 1;
		sym.n_sclass = C_STAT;
		owrite((char *)&sym, sizeof(sym));
	}
	/* Count symbols so symbol section length is known. */
	symnum = C_NSEGS;
	for (i=0; i < NSHASH; ++i) {
		for (sp = hash2[i]; sp != NULL; sp = sp->s_fp) {
			if (isglobal(sp) || (!islabel(sp) && !isdef(sp)))
				sp->s_ref = symnum++;
		}
	}
	coff_hdr.f_nsyms = symnum;		/* symbol count */
	ssize = sizeof(long);			/* string segment size */
	sseek = dseek + symnum * sizeof(sym) + ssize;	/* first string seek */
	symnum = C_NSEGS;
	for (i=0; i < NSHASH; ++i) {
		for (sp = hash2[i]; sp != NULL; sp = sp->s_fp) {
			if (isdef(sp) || islabel(sp))
				sp->s_value += seg[sp->s_seg].s_mseek;
			if (isglobal(sp) || (!islabel(sp) && !isdef(sp))) {
				/* Write global or external symbol. */
				sp->s_ref = symnum++;
				len = strlen(sp->s_id);
				if (len <= SYMNMLEN)
					strncpy(sym.n_name, sp->s_id, SYMNMLEN);
				else {
					/* Spill long name to string table. */
					dseek = ftell(ofp);
					sym.n_zeroes = 0L;
					sym.n_offset = ssize;
					oseek(sseek);
					sput(sp->s_id);
					sseek += len + 1;
					ssize += len + 1;
					oseek(dseek);
				}
				sym.n_value = sp->s_value;
				sym.n_sclass = C_EXT;
				if (isdef(sp))
					sym.n_scnum = segindex[sp->s_seg] + 1;
				else
					sym.n_scnum = C_UNDEF;
				owrite((char *)&sym, sizeof(sym));
			}
		}
	}
	/* Write string table size if nonempty. */
	if (ssize != sizeof(long))
		owrite((char *)&ssize, sizeof(ssize));	

	/* Copy out code. */
	dotseg = SCODE;
	coff_seg = segindex[dotseg];
	txtdot = dot = 0;
	txtp = &txt[0];
	relp = &rel[0];
	while ((op = bget()) != TEND) {
		if (op == TENTER) {
			notenuf();
			seg[dotseg].s_dot = dot;
			dotseg = bget();
			coff_seg = segindex[dotseg];
			txtdot = dot = seg[dotseg].s_dot;
			continue;
		}
		enuf(4, sizeof(RELOC));		/* leave space for next op */
		if (isbyte = ((op & TTYPE) == TBYTE)) {
			nd = 1;
			data = bget();
		} else if (isword = ((op & TTYPE) == TWORD)) {
			nd = 2;
			data = iget();
		} else if ((op & TTYPE) == TLONG) {
			nd = 4;
			data = iget();
		} else
			cbotch("unrecognized op byte: 0x%x", op);
		if (issym = ((op & TSYM) != 0)) {
			sp = pget();
			if (isdef(sp) || islabel(sp) || isbss(sp))
				data += sp->s_value;
		}
		if (ispcr = ((op & TPCR) != 0))
			data -= dot + nd;

		/* Write text. */
		for (i = 1; i <= nd; i++) {
			*txtp++ = data;
			data >>= 8;
		}

		/* Write relocation item if required. */
		if (issym || ispcr) {
			rp = (RELOC *)relp;
			rp->r_vaddr = dot + seg[dotseg].s_mseek;
			if (issym) {
				if (isdef(sp) || islabel(sp))
					rp->r_symndx = segindex[sp->s_seg];
				else
					rp->r_symndx = sp->s_ref;
			} else
				rp->r_symndx = coff_seg;
			if (ispcr)
				rp->r_type = (isbyte) ? R_PCRBYTE
					   : (isword) ? R_PCRWORD : R_PCRLONG;
			else
				rp->r_type = (isbyte) ? R_DIR8
					   : (isword) ? R_DIR16 : R_DIR32;
			relp += sizeof(RELOC);
		}
		dot += nd;
	}

	/* Flush buffers. */
	notenuf();

	/* Write COFF header. */
	coff_hdr.f_magic = C_386_MAGIC;
	coff_hdr.f_nscns = C_NSEGS;
	coff_hdr.f_timdat = time(NULL);
	coff_hdr.f_opthdr = 0;
	coff_hdr.f_flags = F_AR32WR | F_LLNO | L_SYMS;
	oseek(0L);
	owrite((char *)&coff_hdr, sizeof(coff_hdr));

	/* Write section headers. */
	for (shp = &scn_hdr[C_CODE_SEG]; shp < &scn_hdr[C_NSEGS]; ++shp)
		owrite((char *)shp, sizeof(*shp));
}

/* Buffering and output writing routines. */
/*
 * Make sure there is enough room in the text and relocation buffers
 * for nt bytes of text and nr bytes of relocation.
 */
enuf(nt, nr)
{
	if (txtp+nt > &txt[NTXT] || relp+nr > &rel[NREL])
		notenuf();
}

/*
 * 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 "txtdot" to that base.
 */
notenuf()
{
	register int n;

	if ((n = txtp-txt) != 0) {
		dbprintf(("notenuf: %d text bytes\n", n));
		dbprintf(("seek to txtdot=%d + seg[%d].s_dseek=%ld\n", txtdot, dotseg, seg[dotseg].s_dseek));
		oseek(txtdot + seg[dotseg].s_dseek);
		owrite(txt, n);
		if ((n = relp-rel) != 0) {
			dbprintf(("notenuf: %d reloc bytes\n", n));
			dbprintf(("seek to reldot[%d]=%d + relptr=%ld\n", coff_seg, reldot[coff_seg], scn_hdr[coff_seg].s_relptr));
			oseek(reldot[coff_seg] + scn_hdr[coff_seg].s_relptr);
			owrite(rel, n);
			reldot[coff_seg] += n;
			relp = rel;
		}
	}
	txtp = txt;
	txtdot = dot;
}

/*
 * Seek output file, checking for seek error.
 */
oseek(l) long l;
{
	if (fseek(ofp, l, SEEK_SET) == -1L)
		cfatal("seek to %ld failed", l);
}

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

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

unix.superglobalmegacorp.com

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