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

/*
 * coff format output handler.
 */
#include <asm.h>
#include <coff.h>
#include <utype.h>
#include <symtab.h>

#define WHERE 0x40A09C

#define trace(n) printf("Trace %d\n", n);

#define CMOD 2		/* clump every 2 bytes */
#define LIMIT 10	/* bytes of data per line */
#define STARTP 31	/* start source at. Must be n * 8 -1 */
#define DATABUF 512	/* size of data buffer */
#define RELBUF 128	/* entries in relocation buffer */
#define LINEBUF 128	/* entries in line number buffer */
#define MANSEG 3	/* Segments that must go out */
#define ROUNDR 3	/* used to round segments */

typedef struct seg seg;
struct seg {		/* coff section header */
	char		s_name[8];	/* section name */
	long		s_paddr;	/* physical address, aliased s_nlib */
	long		s_vaddr;	/* virtual address */
	long		s_size;		/* section size */
	long		s_scnptr;	/* file ptr to raw data for section */
	long		s_relptr;	/* file ptr to relocation */
	long		s_lnnoptr;	/* file ptr to line numbers */
	unsigned short	s_nreloc;	/* number of relocation entries */
	unsigned short	s_nlnno;	/* number of line number entries */
	long		s_flags;	/* flags */

	/* Extra data connected with this to allow running this segment */
	long		data_seekad;	/* next data seek address */
	long		relo_seekad;	/* next relocation seek address */
	long		line_seekad;	/* next line seek address */
	long		curadd;		/* current address this segment */
	long		hiadd;		/* hi address this pass */
	short		segSeq;		/* Segment sequence no */

	char *bp;			/* data buffer pointer */
	RELOC *relBp;			/* relocation buffer pointer */
	LINENO *lineBp;			/* line number buffer pointer */
	char buf[DATABUF];		/* data buffer */
	RELOC relBuf[RELBUF];		/* relocation entry buffer */
	LINENO lineBuf[LINEBUF];	/* line number entry buffer */
};

static long *tracker;	/* for debugging */

static seg *segs, *segend;	/* segment bases */
static seg *cseg;		/* current segment */

static unsigned short ct, pos, sects, symbs, usects;
static long datapos, relpos, linepos, sympos, debpos;
static long strOff = 4;
static long lastSeek;
static FILE *ofp;		/* output file */

static int coffDefCt;		/* count of .def in file */
static int coffAuxCt;		/* aux records to be written */
static int coffEfcnCt;		/* end of function records */
static int txtAt;		/* DEBUG_RECS from last pass */
#define DEBUG_RECS (coffDefCt + coffAuxCt - coffEfcnCt)
#define USECTS (txtAt ? usects * 2 : usects)
static char defSw;		/* in a .def statement */
static char auxSw;
static char efcnSw;

struct xsym {	/* Symbol for debugging becomes SYMENT and maybe auxent */
	int	symno;
	int	value;
	short	scnum;
	short	type;
	char	sclass;
	char	numaux;
	AUXENT	aux;	/* aux record data */
	char	*name;	/* name if there is one */
};

static struct xsym *syms;		/* all the debug stuff */
static struct xsym *symptr;		/* currently build debug stuff */

union word {
	unsigned char uc[2];
	unsigned short us;
};

union full {
	unsigned char uc[4];
	unsigned long ul;
};

/*
 * output spaces and tabs to a position, then output a character.
 */
static void
outTo(to, s)
{
	int i;

	if(!pos)
		sTitle();

	for (to += (' ' == s); (i = ((pos | 7) + 1)) <= to; pos = i)
		putchar('\t');

	for (; pos < to; pos++)
		putchar(' ');

	if (' ' != s)
		putchar(s);
}

/*
 * Do titles.
 */
sTitle()
{
	static short pageno;

	if(pswitch && (++linect > nlpp)) {
		if(pageno)
			printf("\n\n\n\n\n");
		printf(
	"\n\nMark Williams 80386 Assembler\t%s\t%s\tPage %d\n\n",
			dTime, title, ++pageno);
		linect = 0;
	}
}

/*
 * output source line
 */
outLine(p, s)
char *p, s;
{
	register char c;
		
	if ((2 != pass) ||
	    !lswitch ||
	    (!mlistsw && (NULL != macExp)) ||
	    (NULL == p))
		return;

	outTo(STARTP, s);
	for (; (c = *p++) && ('\n' != c); pos++) {
		if (lineSize <= pos) {
			putchar('\n');
			pos = 0;
			outTo(STARTP, '|');
		}
		if ('\t' == c)
			pos |= 7;
		putchar(c);
	}
	putchar('\n');
	pos = ct = 0;
}

/*
 * Write to obj file.
 */
static void
owrite(buf, size)
char *buf;
{
	if (1 != fwrite(buf, size, 1, ofp))
		fatal("Write error on object file");	/**/
	lastSeek += size;
}

/*
 * Seek then Write to obj file.
 */
xwrite(add, buf, size)
long add;
char *buf;
{
	if (add != lastSeek) {
		if (fseek(ofp, add, 0))
			fatal("Seek error on object file");	/**/
		lastSeek = add;
	}
	owrite(buf, size);
}

/*
 * Write actual data.
 */
outData(s)
register seg *s;
{
	register size;

	if (size = s->bp - s->buf) {
		if (s->s_flags != STYP_BSS) {
			xwrite(s->data_seekad, s->buf, size);
			s->data_seekad += size;
		}
		s->bp = s->buf;
	}
}

/*
 * Write relocation records.
 */
outRel(s)
register seg *s;
{
	register size;

	if (size = (char *)s->relBp - (char *)s->relBuf) {
		xwrite(s->relo_seekad, (char *)s->relBuf, size);
		s->relo_seekad += size;
	}
	s->relBp = s->relBuf;
}

/*
 * Write Line records.
 */
outLineRec(s)
register seg *s;
{
	register size;

	if (size = (char *)s->lineBp - (char *)s->lineBuf) {
		xwrite(s->line_seekad, (char *)s->lineBuf, size);
		s->line_seekad += size;
	}
	s->lineBp = s->lineBuf;
}

/*
 * put object data byte to buffer.
 */
binout(b, s)
unsigned short b;
register seg *s;
{
	if (s->bp == (s->buf + DATABUF))
		outData(s);
	*s->bp++ = b;
}


/*
 * Limit data on line. This allows cuts at logical points.
 */
static void
limiter(n)
{
	if (lswitch && (ct + n) > LIMIT) {
		putchar('\n');
		ct = 0;
	}
}

/*
 * list data
 */
outlst(b)
unsigned short b;
{
	if (dot.sg == 3) {	/* BSS */
		static int statem = -1;	/* only one err per line */

		if (statement != statem) {
			statem = statement;

			yyerror("Data defined in .bss");
			/* The \fB.bss\fR segment is uninitialized data.
			 * You cannot place actual values there. */
		}
	}
	binout(b, cseg);

	if (!lswitch)
		return;

	if (!ct) {
		sTitle();
		pos = 4;
		printf("%04lX", dot.loc + segs[dot.sg - 1].s_vaddr);
	}

	if (!(ct % CMOD)) {
		pos++;
		putchar(' ');
	}
	printf("%02X", b & 255);
	pos += 2;
	ct++;
}

/*
 * output unrelocated byte
 */
outab(b)
unsigned short b;
{
	if (2 == pass) {
		limiter(1);
		outlst(b);
	}
	dot.loc++;	/* update location ctr */
}

/*
 * output unrelocated word.
 */
outaw(u)
unsigned short u;
{
	if (2 == pass) {
		union word w;

		w.us = u;
		limiter(2);
		outlst(w.uc[0]);
		outlst(w.uc[1]);
	}
	dot.loc += 2;
}

/*
 * output unrelocated long.
 */
outal(ul)
long ul;
{
	if (2 == pass) {
		union full l;

		l.ul = ul;
		limiter(4);
		outlst(l.uc[0]);
		outlst(l.uc[1]);
		outlst(l.uc[2]);
		outlst(l.uc[3]);
	}
	dot.loc += 4;
}

/*
 * output relocation.
 */
static long
relOut(oper, sw)
register expr *oper;
unsigned sw;
{
	register RELOC *bp;
	register sym *sp;
	register long rv;

	rv = oper->exp;
	if (NULL == (sp = oper->ref) || (sp->type & S_XSYM))
		return(rv);	/* absolute addr */

	bp = cseg->relBp++;
	bp->r_type   = sw;
	bp->r_vaddr  = dot.loc + cseg->s_vaddr;

	/*
	 * Only use symbol references when forced
	 * seems to be required by a bug in the
	 * ESIX linker.
	 */
	if (!(sp->flag & (S_EXREF|S_COMMON))) {
		int seg = segs[sp->sg - 1].segSeq - 1;

		bp->r_symndx = txtAt ? (seg * 2) + txtAt : seg;
	}
	else {
		bp->r_symndx = sp->num;
		if (sp->flag & S_COMMON)
			rv += sp->size;
		rv -= sp->loc;
	}

	if (bp == (cseg->relBuf + (RELBUF - 1)))
		outRel(cseg);

	/* gimmic addr to make .data after .text */
	if ((sp->sg > 1) && !(sp->flag & S_COMMON))
		rv += segs[sp->sg - 1].s_vaddr;

	return(rv);
}
		
/*
 * output relocated byte
 */
outrb(oper, sw)
expr *oper;
int sw;		/* 0 = Relative address, 1 = PC relative address */
{
	if (2 == pass) {
		limiter(1);
		if (sw)
			outlst((unsigned short)(relOut(oper, R_PCRBYTE) -
						(dot.loc + 1)));
		else
			outlst((unsigned short)relOut(oper, R_RELBYTE));
	}
	else if (NULL != oper->ref)
		cseg->s_nreloc++;
	dot.loc++;
}

/*
 * output relocated word.
 */
outrw(oper, sw)
expr *oper;
int sw;		/* 0 = Relative address, 1 = PC relative address */
{
	union word w;

	if (2 == pass) {
		if (sw)
			w.us = relOut(oper, R_PCRWORD) - (dot.loc + 2);
		else
			w.us = relOut(oper, R_DIR16);

		limiter(2);
		outlst(w.uc[0]);
		outlst(w.uc[1]);
	}
	else if (NULL != oper->ref)
		cseg->s_nreloc++;
	dot.loc += 2;
}

/*
 * output relocated long.
 */
outrl(oper, sw)
expr *oper;
int sw;		/* 0 = Relative address, 1 = PC relative address */
{
	union full l;

	if (2 == pass) {
		if (sw)
			l.ul = relOut(oper, R_PCRLONG) - (dot.loc + 4);
		else
			l.ul = relOut(oper, R_DIR32);

		limiter(4);
		outlst(l.uc[0]);
		outlst(l.uc[1]);
		outlst(l.uc[2]);
		outlst(l.uc[3]);
	}
	else if (NULL != oper->ref)
		cseg->s_nreloc++;
	dot.loc += 4;
}

/*
 * Output symbol table string.
 */
outSymStr(sp)
register sym *sp;
{
	register i;
	register char *name;

	name = SYMNAME(sp);
	if ((i = strlen(name)) > SYMNMLEN)
		owrite(name, i + 1);
}

static void showIt(sp)
sym *sp;
{
	int i;
	char *name;

	i = strlen(name = SYMNAME(sp));
	fprintf(stderr, "Trace %X, '%s' flag %d len %d num %d\n",
		 sp, name, sp->flag, i, sp->num);
}

/*
 * output symbol table entry.
 */
SYMENT *
outSym(sp)
register sym *sp;
{
	static SYMENT s;
	int i;
	register char *name;

	clear(&s);

	i = strlen(name = SYMNAME(sp));

	if (i > SYMNMLEN) {
		s.n_zeroes = 0;
		s.n_offset = strOff;
		strOff += i + 1;
	}
	else
		strncpy(s._n._n_name, name, SYMNMLEN);

	if (sp->sg < 0)
		s.n_scnum = sp->sg;
	else
		s.n_scnum = segs[sp->sg - 1].segSeq;
	s.n_value = sp->loc;
	s.n_sclass = C_STAT;

	if (sp->flag & S_EXDEF) {
		s.n_sclass = C_EXT;
		if (sp->flag & S_COMMON) { /* common */
			s.n_value = (sp->size ? sp->size : 1);
			s.n_scnum = 0;
		}
	}
	if (sp->flag & S_EXREF) {
		s.n_scnum  = 0;
		s.n_value  = 0;
		s.n_sclass = C_EXT;
	}

	/* gimmic addr to make .data after .text */
	if (s.n_scnum > 1)
		s.n_value += segs[sp->sg - 1].s_vaddr;

	owrite((char *)&s, sizeof(s));
	return (&s);
}

/*
 * Go from pass 0 to pass 1 or 2
 */
newPass(fn)
char *fn;
{
	register seg *s;
	unsigned size;
	long xaddr;
	
	if ((cseg->curadd = dot.loc) > cseg->hiadd)
		cseg->hiadd = cseg->curadd;
	cseg = segs;	/* return to .text */
	defCt = macNo = dot.loc = 0;
	if ((txtAt = DEBUG_RECS) && !pass) {
		xpass = 1;	/* force another pass */
		symptr = syms = alloc(coffDefCt * sizeof(*syms));
	}
	longMode = pass = dot.sg = 1;
	if (indPass()) {	/* take an extra pass */
		usects = 0;
		for (s = segs; s < segend; s++) {
			if (s->hiadd || usects < MANSEG)
				usects++;
			s->segSeq = usects;
			s->bp = s->buf;
			s->relBp = s->relBuf;
			s->lineBp = s->lineBuf;
			s->s_nlnno = s->s_nreloc = s->hiadd = s->curadd = 0;
		}
		symGlob(txtAt + USECTS); /* fix symbol table */
		coffDefCt = coffAuxCt = coffEfcnCt = 0;
		return;
	}

	pass   = 2;	/* last pass */
	linect = nlpp;
	usects = xaddr = datapos = relpos = linepos = 0;
	ofp = xopen(fn, "wb");
	
	for (s = segs; s < segend; s++) {
		if (s->hiadd || usects < MANSEG)
			usects++;
		s->s_paddr = s->s_vaddr = xaddr;
		s->hiadd += ROUNDR;		/* Round up */
		s->hiadd &= ~ROUNDR;
		xaddr += s->s_size = s->hiadd;
		s->data_seekad = datapos; /* temp value */
		s->s_relptr = relpos;
		s->s_lnnoptr = linepos;
		if (s->s_flags != STYP_BSS) {
			datapos += s->hiadd;
			relpos  += s->s_nreloc * RELSZ;
			linepos += s->s_nlnno  * LINESZ;
		}
	}
	size =  sizeof(FILEHDR) + (usects * sizeof(SCNHDR));
	debpos  = size + datapos + relpos + linepos;
	sympos  = debpos + (txtAt * SYMESZ);
	linepos = size + datapos + relpos;
	relpos  = size + datapos;

	if (fseek(ofp, lastSeek = sympos, 0))
		fatal("Seek error on object file");	/**/

	usects = 0;
	for (s = segs; s < segend; s++) {
		SYMENT sym;
		AUXENT aux;

		if (s->hiadd || usects < MANSEG)
			usects++;
		else
			continue;

		/* write symbol records for segments */
		clear(&sym);
		s->segSeq = usects;
		sym.n_sclass = C_STAT;
		sym.n_value = s->s_vaddr;
		memcpy(sym._n._n_name, s->s_name, SYMNMLEN);
		sym.n_scnum = usects;
		sym.n_numaux = txtAt ? 1 : 0;
		owrite((char *)&sym, sizeof(sym));

		if (sym.n_numaux) {
			aux.ae_scnlen = s->s_size;
			aux.ae_nreloc = s->s_nreloc;
			aux.ae_nlinno = s->s_nlnno;
			owrite((char *)&aux, sizeof(aux));
		}

		if (s->hiadd && (s->s_flags != STYP_BSS))
			s->s_scnptr = s->data_seekad += size;
		else
			s->s_scnptr = s->data_seekad = 0;

		if (s->s_nreloc && (s->s_flags != STYP_BSS))
			s->relo_seekad = s->s_relptr += relpos;
		else
			s->relo_seekad = s->s_relptr = 0;

		if (s->s_nlnno && (s->s_flags != STYP_BSS))
			s->line_seekad = s->s_lnnoptr += linepos;
		else
			s->line_seekad = s->s_lnnoptr = 0;
		s->hiadd = s->curadd = 0;
	}

	sympos = ftell(ofp);	/* continue the symbol table from here */

	/* fix the symbol table setting numbers */
	symGlob(txtAt + USECTS);
	coffDefCt = coffAuxCt = coffEfcnCt = 0;
}

/*
 * write record header then segment headers.
 */
static void
writeHeader()
{
	register seg *s;
	FILEHDR head;
	int i;
	long loadd;

	head.f_magic = C_386_MAGIC;
	time(&head.f_timdat);
	head.f_nsyms = symbs;
	head.f_symptr = debpos;
	head.f_opthdr = 0;
	head.f_flags = 0;
	head.f_nscns = usects;

	xwrite(0L, (char *)&head, sizeof(head));
	for (loadd = i = 0, s = segs; s < segend; s++) {
		if (s->hiadd || i < MANSEG) {
			i++;
			owrite(s, sizeof(SCNHDR));
		}
	}
}

/*
 * Finish any output.
 */
cleanUp()
{
	int pad;
	register seg *s;

	s = cseg;		/* close out current seg */
	if(s->hiadd < (s->curadd = dot.loc))
		s->hiadd = s->curadd;

	if (coffDefCt)	/* Write debug symbols */
		writeDebug();

	fseek(ofp, sympos, 0);

	symDump(outSym, txtAt);	/* write ordinary symbols */

	symbs = (ftell(ofp) - debpos) / SYMESZ; /* figure sym ct from loc */

	if (strOff > 4) {
		owrite(&strOff, sizeof(strOff)); /* write length of tail */
		writeDebugLong();   /* dump symbols that are too long */
		symDump(outSymStr, txtAt);	
	}

	writeHeader();	/* now we know header data */

	for (s = segs; s < segend; s++) {
		if (s->s_flags == STYP_BSS)
			continue;

		/* go to end of segment */
		if (s->curadd != s->hiadd)
			doOrg(NULL, NULL);

		/* pad with nop or zero */
		pad = (s->s_flags == STYP_TEXT) ? NOP : 0;
		for (; s->hiadd & ROUNDR; s->hiadd++)
			binout(pad, s);
		outData(s);
		outRel(s);
		outLineRec(s);
	}
}

/*
 * org command
 */
doOrg(label, oper)
parm *label;
data *oper;
{
	register seg *s;
	long from, to;
	char pad;

	buildlab(label);

	from = dot.loc;
	s = cseg;
	if (pass == 2)
		outData(s);
	s->curadd = dot.loc;		/* first make segment current */
	if (dot.loc > s->hiadd)
		s->hiadd = dot.loc;
	
	/* process org */
	switch ((NULL == oper) ? 'n' : oper->type) {
	case 'n':
		to = s->hiadd;	/* org to hi spot in segment */
		break;
	case 'd':
	case 's':
		yyerror("Org to invalid value");
		/* You may not \fB.org\fR to doubles or strings. */
		return (1);
	case 'y':
		if (oper->d.y->sg != dot.sg) {
			yyerror("Org to wrong segment");
			/* You must \fB.org\fR to the current segment. */
			return (1);
		}
		to = oper->d.y->loc;
		break;
	case 'l':
		to = oper->d.l;	/* org where requested */
	}

	if ((pass != 2) || (s->s_flags == STYP_BSS)) { /* no disk work */
		s->curadd = dot.loc = to;	/* make segment current again */
		if (to > s->hiadd)
			s->hiadd = dot.loc;
		return (0);
	}
	if (to <= s->hiadd) {	/* no pad if we've been there */
		s->curadd = dot.loc = to;
		s->data_seekad += to - from;
		return (0);
	}
	from = s->curadd = dot.loc = s->hiadd;	/* seek to the old end */
	s->data_seekad += s->hiadd - from;

	pad = (s->s_flags == STYP_TEXT) ? NOP : 0; /* pad out */
	for (;from < to; from++)
		binout(pad, s);
	s->curadd = dot.loc = to;	/* make segment current again */
	if (to > s->hiadd)
		s->hiadd = dot.loc;
	return (0);
}

/*
 * Initialize segment information.
 */
segInit()
{
	int i;
	register seg *s;

	static char *segclass[] = {
		".text", ".data", ".bss"
	};
	static long segflag[] = {
		STYP_TEXT, STYP_DATA, STYP_BSS
	};

	cseg = segs = alloc(sizeof(*segs) * MANSEG);
	segend = segs + MANSEG;

	for (i = 0, s = segs; s < segend; s++, i++) {
		strncpy(s->s_name, segclass[i], SYMNMLEN);
		s->s_flags = segflag[i];
		s->segSeq = ++sects;
		s->bp = s->buf;
		s->relBp = s->relBuf;
		s->lineBp = s->lineBuf;
	}
}

/*
 * .ident and .version set stuff in the comment section.
 */
cmnt(op, p)
opc *op;
parm *p;
{
}

/*
 * coff debugging statements.
 */
coffFile(s)
parm *s;
{
#ifdef NODEBUG
	return;
#else
	coffDefCt++;
	coffAuxCt++;
	if (2 == pass) {
		symptr->sclass = C_FILE;
		symptr->scnum  = N_DEBUG;
		symptr->numaux = 1;
		if ('"' == s->str[0]) {
			char *p;

			if (NULL != (p = strchr(s->str + 1, '"')))
				*p = 0;
			strncpy(symptr->aux.ae_fname, s->str + 1, FILNMLEN);
		}
		else
			strncpy(symptr->aux.ae_fname, s->str, FILNMLEN);
		symptr->name = ".file";
		symptr++;
	}
#endif
}

coffDef(s)
parm *s;
{
#ifdef NODEBUG
	return;
#else
	if (pass) {	/* initialize new symbol */
		if (defSw)
			yywarn("missing .endef");
		symptr->scnum = N_ABS;
		if (NULL != symptr->name)
			free(symptr->name);
		symptr->name  = scpy(s->str, 0);
		symptr->symno = DEBUG_RECS;
		defSw = 1;
	}
#endif
}

coffEndef()
{
#ifdef NODEBUG
	return;
#else
	if ((1 == pass) && (symptr->scnum != N_DEBUG))
		symReNumber(symptr->name, DEBUG_RECS);

	if (2 == pass) {
		register struct xsym *s;

		switch (symptr->sclass) {
		case C_BLOCK:
			if (strcmp(symptr->name, ".eb"))
				break;
			for (s = symptr - 1; s != syms; s--)
				if (C_BLOCK == s->sclass &&
				    !strcmp(s->name, ".bb") &&
				    !s->aux.ae_endndx) {
					s->aux.ae_endndx = DEBUG_RECS + 2;
					break;
				}
			if (s == syms)
				yywarn(".eb does not connect to .bb");
				/* A .eb statement does not connect to a
				 * .bb statement */
			break;

		case C_EFCN:	/* end of function marker */
			for (s = symptr - 1; s != syms; s--) {
				if (!strcmp(symptr->name, s->name)) {
					short type;

					/* if this is a function at any level */
					for (type = s->type & ~N_BTMASK;
					     type && !ISFCN(type);
					     type >>= N_TSHIFT)
					 	;

					if (type)
						break;
				}
			}
			if (s == syms)
				yywarn(".type -1 does not connect");
				/* A type of -1 C_EFCN does not connect to
				 * a .def of a function */
			else {
				s->aux.ae_fsize = symptr->value - s->value;
				s->aux.ae_endndx = DEBUG_RECS;
			}
		}
		symptr->numaux = auxSw;
		symptr++;
		if (!defSw)
			yywarn(".endef must follow .def"); /* */
	}
	coffDefCt++;			/* we need a spot to remember this */
	coffEfcnCt += efcnSw;		/* C_EFCN don't write to table */
	if (!efcnSw)			/* They don't have aux records */
		coffAuxCt += auxSw;
	auxSw = defSw = efcnSw = 0;
#endif
}

/*
 * .type command
 */
coffType(n)
long n;
{
#ifdef NODEBUG
	return;
#else
	if (ISFCN(n)) { /* function build a line record */
		register LINENO *bp;

		auxSw = 1;
		if (2 != pass)
			cseg->s_nlnno++;
		else {
			bp = cseg->lineBp++;
			bp->l_lnno = 0;
			bp->l_addr.l_symndx = DEBUG_RECS;
		
			if (bp == (cseg->lineBuf + (LINEBUF - 1)))
				outLineRec(cseg);
		}
	}

	if (2 == pass) {
		if (!defSw)
			yywarn(".type not in .endif");
			/* Debug command .type must be in .endif */
		symptr->type = n;
	}
#endif
}

coffVal(item)
data *item;
{
#ifdef NODEBUG
	return;
#else
	SYMENT *s;

	if (2 != pass)
		return;
	if (!defSw)
		yywarn(".val must follow .def"); /* */

	if ('y' == item->type) {
		sym *sp = item->d.y;

		if (sp->flag & S_COMMON) {
			symReNumber(symptr->name, DEBUG_RECS);
			symptr->scnum = N_UNDEF;
			symptr->value = sp->size;
		}
		else {
			symptr->scnum = sp->sg;
			symptr->value = sp->loc;
		}
	}
	else
	 	symptr->value = item->d.l;
#endif
}

coffScl(n)
long n;
{
#ifdef NODEBUG
	return;
#else
	if (C_EFCN == n)
		efcnSw = 1;
	if (!pass)
		return;
	if (!defSw)
		yywarn(".scl must follow .def"); /* */
	if (ISTAG(n))
		symptr->scnum = N_DEBUG;
	symptr->sclass = n;
#endif
}

coffSize(n)
long n;
{
#ifdef NODEBUG
	return;
#else
	auxSw = 1;
	if (2 != pass)
		return;
	if (!defSw)
		yywarn(".size must follow .def"); /* */
	symptr->aux.ae_size = n;
#endif
}

coffDim(n, d)
long n;
int d;
{
#ifdef NODEBUG
	return;
#else
	auxSw = 1;
	if (2 != pass)
		return;
	if (!defSw) {
		yywarn(".dim must follow .def"); /* */
		return;
	}
	if (DIMNUM <= d) {
		yywarn(".dim statement too complex");
		/* A .dim statement may contain no more than 4 dimensions. */
		return;
	}
	symptr->aux.ae_dimen[d] = n;
#endif
}

coffTag(p)
parm *p;
{
#ifdef NODEBUG
	return;
#else
	struct xsym *s;

	auxSw = 1;
	if (2 != pass)
		return;
	for (s = symptr - 1; s != syms; s--) {
		if (ISTAG(s->sclass) && !strcmp(p->str, s->name)) {
		    	if (C_EOS == symptr->sclass)
				s->aux.ae_endndx = symptr->symno + 2;
			symptr->aux.ae_tagndx = s->symno;
			break;
		}
	}
	if (s == syms)
		yywarn(".tag does not connect");
		/* This tag fails to connect to an earlier unconnected .def
		 * of the same name and a proper n_sclass.
		 */
#endif
}

coffLn(n)
long n;
{
#ifdef NODEBUG
	return;
#else
	register LINENO *bp;

	if (2 != pass)
		cseg->s_nlnno++;
	else {
		bp = cseg->lineBp++;
		bp->l_lnno = n;
		bp->l_addr.l_paddr = dot.loc;
		
		if (bp == (cseg->lineBuf + (LINEBUF - 1)))
			outLineRec(cseg);
	}
#endif
}

coffLine(n)
long n;
{
#ifdef NODEBUG
	return;
#else
	auxSw = 1;
	if (2 != pass)
		return;
	if (!defSw)
		yywarn(".line must follow .def"); /* */
	symptr->aux.ae_lnno = n;	
#endif
}

/*
 * Write debug records.
 */
writeDebug()
{
	register struct xsym *s, *ends;
	int ct = 0, act = 0;

	fseek(ofp, lastSeek = debpos, 0);
	for (ends = (s = syms) + coffDefCt; s != ends; s++) {
		int i;
		SYMENT sym;

		if (C_EFCN == s->sclass)
			continue;

		sym.n_sclass = s->sclass;
		sym.n_value  = s->value;
		sym.n_scnum  = s->scnum;
		sym.n_type   = s->type;
		sym.n_numaux = s->numaux;

		if ((i = strlen(s->name)) > SYMNMLEN) {
			sym.n_offset = strOff;
			sym.n_zeroes = 0;
			strOff += i + 1;
		}
		else
			strncpy(sym.n_name, s->name, SYMNMLEN);
		
		ct++;
		owrite(&sym, SYMESZ);
		if (sym.n_numaux) {
			act++;
			owrite(&(s->aux), AUXESZ);
		}
	}
	
}

writeDebugLong()
{
	register struct xsym *s, *ends;

	for (ends = (s = syms) + coffDefCt; s != ends; s++) {
		int i;

		if (C_EFCN == s->sclass)
			continue;

		if ((i = strlen(s->name)) > SYMNMLEN)
			owrite(s->name, i + 1);
	}
}
	
/*
 * .comm and .lcomm commands.
 * Improve later.
 */
comm(op, p, n)
opc *op;
parm *p;
long n;
{
	if (NULL == p) {
		yyerror(".comm must have tag");
		/* The format of \fB.comm\fR is \fB.comm name, size\fR. */
		return;
	}
	if (op->code == 2) {
		sym *s;

		s = symLookUp(p->str, S_LOCAL, 0L, op->code + 1);
		s->size = n;
		s->flag = S_EXDEF|S_COMMON;
	}
}

/*
 * segment command.
 */
void
segment(op, p, n)
opc *op;
parm *p;
long n;
{
	register seg *s;
	sym *rv;
	static int previous = 0;
	int thisSg;

	/* Implement one level segment stack */
	if (10000 != op->code) {
		thisSg = op->code;
		previous = dot.sg - 1;	/* save where we were */
	}
	else	/* .previous pops the stack */
		thisSg = previous;

	s = segs + thisSg;

	if (NULL == p) {	/* segment change */
		if ((cseg->curadd = dot.loc) > cseg->hiadd)
			cseg->hiadd = cseg->curadd;

		cseg = s;
		dot.loc = s->curadd;
		dot.sg = thisSg + 1;
		return;
	}

	/* set up data */
	rv = symLookUp(p->str, S_LOCAL, s->curadd, thisSg + 1);
	rv->size = n;
	s->curadd += n;
	if (s->curadd > s->hiadd)
		s->hiadd = s->curadd;
	return;
}

/*
 * Switch to a section by name.
 * add it if required.
 */
void
section(name)
char *name;
{
	int motion, i;
	char *oldsegs;
	register seg *s;
	static opc segOp = { 0, S_SEGMENT };

	/* These are common segment names with their flags */
	static char *segclass[] = {
		".init", ".fini", ".rodata",
		".comment", ".ctors", ".dtors"
	};
	static long segflag[] = {
		STYP_TEXT, STYP_DATA, STYP_DATA,
		STYP_INFO, STYP_DATA, STYP_DATA
	};

	/* Look for section in segment list */
	for (segOp.code = 0; segOp.code < sects; segOp.code++) {
		if (!strncmp(name, segs[segOp.code].s_name, 8)) {
			segment(&segOp, NULL, 0L);
			return;
		}
	}

	/* realloc segment list with room for one more */
	oldsegs = (char *)segs;
	if (NULL == (segs = realloc(segs, sizeof(*segs) * ++sects)))
		fatal("Out of memory"); /**/

	/* adjust pointers to segment list */
	motion = (char *)segs - oldsegs;
#define adjust(ptr) ptr = (char *)(((char *)(ptr)) + motion)
	adjust(cseg);
	adjust(segend);
	for (s = segs; s < segend; s++) {
		adjust(s->bp);
		adjust(s->relBp);
		adjust(s->lineBp);
	}
#undef adjust
	segend++;

	/* build new entry on segment list */
	memset(s, '\0', sizeof(*s));
	strncpy(s->s_name, name, SYMNMLEN);
	
	s->s_flags = STYP_TEXT;		/* set default */
	for (i = 0; i < 6; i++) {	/* look at common names */
		if (!strcmp(name, segclass[i])) {
			s->s_flags = segflag[i];
			break;
		}
	}

	s->segSeq = sects - 1;
	s->bp = s->buf;
	s->relBp = s->relBuf;
	s->lineBp = s->lineBuf;

	segment(&segOp, NULL, 0L);	/* switch to the new entry */
}

unix.superglobalmegacorp.com

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