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

/*
 * This file writes writes Intel iAPX-86 OMF with csd debugging information.
 * Based on outomf.c, but with MWC CSD-format debug info (as in outrel.c)
 * instead of Intel format.
 * The 'out...' routines write to a temporary file during code assembly.
 * At the end of assembly, 'copycode' uses the 'put...' routines
 * to write the object file.
 * This is necessary: SEGDEF records must be written before
 * LEDATA and FIXUPP records, but each SEGDEF includes the size
 * of the segment in bytes.
 * However, the size of the DEBUG segment is fixed up ex post facto.
 */

/*
 * Reference: "8086 Relocatable Object Formats,"
 * Intel 121748-001 (C) Intel 1981.
 */

#ifdef	vax
#include "INC$LIB:cc2.h"
#include "INC$LIB:debug.h"
#else
#include "cc2.h"
#include "debug.h"
#endif

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

#ifndef __LINE__
#define	__LINE__	0
#endif

#if !TINY
#define	dbrpt(x,y)	_dbrpt(x,y)
#else
#define	dbrpt(x,y)	/* _dbrpt(x,y) */
#endif

/*
 * Scratch file opcodes.
 * Flags are or'ed in to TBYTE and TWORD opcodes only.
 */
#define	TTYPE	0x07			/* Type */
#define	TPCR	0x08			/* PC rel flag */
#define	TSYM	0x10			/* Symbol based flag */

#define	TEND	0x00			/* End marker */
#define	TENTER	0x01			/* Enter new area */
#define	TBYTE	0x02			/* Byte data */
#define	TWORD	0x03			/* Word data */
#define	TCODE	0x04			/* Code segment base */
#define	TDATA	0x05			/* Data segment base */
#define	TBASE	0x06			/* External segment base */
#define	TDLAB	0x07			/* Debug label */
#define	TDLOC	0x08			/* Debug location */

#if	EMUFIXUPS
/*
 * If EMUFIXUPS is defined at compile time, the generated output writer
 * targets 8087 instructions with magic "M:..." fixups.
 * The linker can then create objects which use either 8087 hardware
 * or software floating point emulation; in the latter case, the
 * linker changes the 8087 instructions into traps to the emulator.
 */
#define	T8087	0xE0			/* 8087 flags */
#define	TWT	0x20			/* M:_WT  */
#define	TWST	0x40			/* M:_WST */
#define	TWES	0x60			/* M:_WES */
#define	TWCS	0x80			/* M:_WCS */
#define	TWSS	0xA0			/* M:_WSS */
#define	TWDS	0xC0			/* M:_WDS */
#endif

/*
 * OMF types.
 */
#define	THEADR	0x80			/* Translator module header */
#define	COMENT	0x88			/* Comment */
#define	MODEND	0x8A			/* Module end */
#define	EXTDEF	0x8C			/* External definition (reference) */
#define	TYPDEF	0x8E			/* Type definition */
#define	PUBDEF	0x90			/* Public definition (definition) */
#define	LNAMES	0x96			/* List of names */
#define	SEGDEF	0x98			/* Segment definition */
#define	GRPDEF	0x9A			/* Group definition */
#define	FIXUPP	0x9C			/* Fixups */
#define	LEDATA	0xA0			/* Enumerated data */
#define	LIDATA	0xA2			/* Iterated data */

/*
 * Some OMF fields and flags.
 */
#define	BYTE	(0x01<<5)		/* Byte alignment */
#define	PARA	(0x03<<5)		/* Paragraph alignment */
#define	BIG	0x02			/* 64k */
#define	CCON	(0x02<<2)		/* C field, concatenate */
#define	CMEM	(0x01<<2)		/* C field, memory */
#define	CSTACK	(0x05<<2)		/* C field, stack */

#define	LOCAT	0x80			/* Locat flag bit */
#define	M	0x40			/* M bit; 0=self rel, 1=seg rel */
#define	LOBYTE	(0x00<<2)		/* Locat */
#define	OFFSET	(0x01<<2)		/* Locat */
#define	BASE	(0x02<<2)		/* Locat */
#define	POINTER	(0x03<<2)		/* Locat */
#define	HIBYTE	(0x04<<2)		/* Locat */

#define	SECWAY	0x04			/* Secondary way */
#define	FD8087	0x36			/* FIXDAT for 8087 fixup */
#define	FSI	(0<<4)			/* Frame segment index */
#define	FGI	(1<<4)			/* Frame group index */
#define	FEI	(2<<4)			/* Frame external index */
#define	FFN	(3<<4)			/* Frame frame number */
#define	FLSEG	(4<<4)			/* Frame of LSEG */
#define	FTARGET	(5<<4)			/* Frame of TARGET object */
#define	FNONE	(6<<4)			/* No frame */
#define	TSI	0			/* Target: segment index */
#define	TGI	1			/* Target: group index */
#define	TEI	2			/* Target: external index */
#define	TFN	3			/* Target: frame */
#define	F	0x80			/* Frame thread used */
#define	T	0x08			/* Target thread used */
#define	FT0	0x00			/* 0 */
#define	FT1	0x10			/* 1 */

#define	VCSD	(isvariant(VTYPES)||isvariant(VDSYMB))

/*
 * Structure to contain debug items on this pass.
 * Debug items are kept in a linked list rooted at 'dbase',
 * with 'dnext' pointing at the most recent item.
 */
struct dbgt {
	struct dbgt	*d_dp;		/* Link */
	int		d_ref;		/* Index number */
	unsigned char	d_class;	/* Storage class */
	unsigned char	d_flag;		/* Flags */
	unsigned char	d_level;	/* Bracket level */
	unsigned char	d_seg;		/* Reloc-style segment */
	unsigned char	d_cseg;		/* C Segment */
	ADDRESS		d_value;	/* Offset in segment */
	int		d_size;		/* Size of d_data */
	char		d_data[];	/* Name and type */
};
/* Flag bits. */
#define	D_GBL	 1
#define	D_LCL	 2
#define	D_TAG	 4
#define	D_NAM	 8
#define	D_LAB	16
#define	D_ENU	32

/*
 * Globals for output writer.
 */
static	int	checksum;		/* For putrecord and putbyte */
static	char	txt[NTXT+5];		/* Text buffer */
static	char	rel[NREL];		/* Relocation buffer */
static	ADDRESS	code_size;		/* Size of CODE */
static	ADDRESS	data_size;		/* Size of DATA */
static	ADDRESS	const_size;		/* Size of CONST */
static	ADDRESS	bss_size;		/* Size of BSS */
static	char	*txtp = txt;		/* Text pointer */
static	char	*relp = rel;		/* Relocation pointer */
static	struct dbgt	*dbase;		/* Root debug list item */
static	struct dbgt	*dnext;		/* Last debug list item */
static	int	level = 0;		/* Debug brace level */
static	int	dline = 0;		/* Most recent line number entry */

#if	EMUFIXUPS
static	int	has8087;		/* Has 8087 code flag */
static	SYM	*wsp[6];		/* Links to emulator symbols */
#endif

#if	VAXFMT
/*
 * The Intel cross software packs the OMF
 * data into 512 byte blocks as 510 byte variable length
 * records, with the last record short.
 */
#define	NVDATA	510			/* Blocksize - 2 */
static	char	vaxbuf[NVDATA];		/* Buffer */
static	char	*vaxptr = vaxbuf;	/* Pointer */
#endif

/*
 * Function declarations.
 */
extern	char		*calloc();
extern	long		ftell();
extern	struct dbgt	*getdbgt();
extern	char		*getmembs();
extern	char		*malloc();
extern	struct dbgt	*newdbgt();
extern	long		putsegdef();
extern	char		*setindex();
extern	char		*setsymid();
extern	char		*strcpy();

/*
 * These tables are indexed by a compiler segment name (SCODE et al)
 * to get an OMF segment index.
 * These tables understand the way the SSTRN segment moves
 * around when the ROM option is given, and
 * are dependent on the order of the calls to putsegdef() in copycode().
 */
static	char	lnonseg[] = {
	1,				/* SCODE => module_CODE */
	1,				/* SLINK => module_CODE */
	1,				/* SPURE => module_CODE */
	2,				/* SSTRN => module_DATA */
	2,				/* SDATA => module_DATA */
	2				/* SBSS  => module_DATA */
};

static	char	lromseg[] = {
	1,				/* SCODE => module_CODE */
	1,				/* SLINK => module_CODE */
	1,				/* SPURE => module_CODE */
	1,				/* SSTRN => module_CODE */
	2,				/* SDATA => module_DATA */
	2				/* SBSS  => module_DATA */
};

static	char	lramseg[] = {
	1,				/* SCODE => module_CODE */
	1,				/* SLINK => module_CODE */
	2,				/* SPURE => module_DATA */
	2,				/* SSTRN => module_DATA */
	2,				/* SDATA => module_DATA */
	2				/* SBSS  => module_DATA */
};

static	char	snonseg[] = {
	1,				/* SCODE => CODE */
	1,				/* SLINK => CODE */
	2,				/* SPURE => CONST */
	3,				/* SSTRN => DATA */
	3,				/* SDATA => DATA */
	3				/* SBSS  => DATA */
};

static	char	sromseg[] = {
	1,				/* SCODE => CODE */
	1,				/* SLINK => CODE */
	2,				/* SPURE => CONST */
	2,				/* SSTRN => CONST */
	3,				/* SDATA => DATA */
	3				/* SDATA => DATA */
};

static	char	sramseg[] = {
	1,				/* SCODE => CODE */
	1,				/* SLINK => CODE */
	3,				/* SPURE => DATA */
	3,				/* SSTRN => DATA */
	3,				/* SDATA => DATA */
	3				/* SDATA => DATA */
};

/*
 * Same game, but for group index codes.
 * This is used only in SMALL model.
 */
static	char	grpindex[] = {
	1,				/* SCODE => CGROUP */
	1,				/* SLINK => CGROUP */
	2,				/* SPURE => DGROUP */
	2,				/* SSTRN => DGROUP */
	2,				/* SDATA => DGROUP */
	2				/* SBSS  => DGROUP */
};

/*
 * Some prefabricated OMF items.
 * These are just blasted out via calls to putrecord().
 */
static	char	lthred[]	= { 0x40, 1,		/* module_CODE */
				    0x41, 2 };		/* module_DATA */
static	char	gdef1[]		= { 7, 0xFF, 1 };
static	char	gdef2[]		= { 8, 0xFF, 2, 0xFF, 3, 0xFF, 4, 0xFF, 5 };
static	char	sthred[]	= { 0x00, 1,		/* Code */
				    0x01, 2,		/* Const */
				    0x02, 3,		/* Data */
				    0x44, 1,		/* Frame -> CGROUP */
				    0x45, 2		/* Frame -> DGROUP */
				};
static	char	typdef[]	= { 0, 0, 0x80 };
static	char	modend[]	= { 0x00 };

/*
** First pass routines.
** Output items to the temporary file.
*/
/*
 * Initialize the code writer.
 */
outinit()
{
#if	MONOLITHIC
#if	EMUFIXUPS
	register int	i;

	has8087 = 0;
	for (i=0; i<6; ++i)
		wsp[i] = NULL;
#endif
	txtp = &txt[0];
	relp = &rel[0];
	dbase = dnext = NULL;
#if	VAXFMT
	vaxptr = &vaxbuf[0];
#endif
#endif
}

/*
 * 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(w);
	dot += 2;
}

/*
 * Output a full byte.
 */
outxb(sp, b, pcrf)
register SYM *sp;
{
	register 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 opcode;

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

#if	EMUFIXUPS
/*
 * Output a one byte opcode for the 8087.
 */
outfb(b)
{
	has8087 = 1;
	bput(TBYTE|TWT);
	bput(b);
	++dot;
}

/*
 * Output a two byte opcode for the 8087.
 */
outfw(w, prefix)
{
	has8087 = 1;
	bput(TWORD|((prefix>>3)+TWST));
	iput(w);
	dot += 2;
}
#endif

#if	0
/*
 * Because the compiler now generates LARGE model code with links,
 * the following routines are currently unused.
 * They are retained for future reference.
 */
/*
 * 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;
}
#endif

/*
 * 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 ofp.
 * Flag the symbol table entry if appropriate.
 * Recursive for DX_MEMBS member lists.
 */
outdlab(l,class)
{
	register int val;
	register SYM *sp;
	int n;

	if (l == 0)
		bput(TDLAB);
	bput(class);

	/* Get line number. */
	iput(iget());

	/* Get value */
	if (class < DC_AUTO)
		;
	else if (class < DC_MOS)
		iput(val = iget());
	else {
		bput(bget());
		bput(bget());
		iput(iget());
	}

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

	/* Check for symbol table entry */
	if (class==DC_GDEF || class==DC_SEX || class==DC_GREF) {
		sp = glookup(id, 0);
		sp->s_flag |= S_PUT;
	} else if (class==DC_SIN) {
		sp = llookup(val, 0);
		sp->s_flag |= S_PUT;
	}

	/* Put name */
	sput(id);

	/* Get type */
	for (;;) {
		switch (bput(bget())) {
		case DT_NONE:
		case DT_CHAR:
		case DT_UCHAR:
		case DT_SHORT:
		case DT_USHORT:
		case DT_INT:
		case DT_UINT:
		case DT_LONG:
		case DT_ULONG:
		case DT_FLOAT:
		case DT_DOUBLE:
		case DT_VOID:
			iput(iget());
			break;
		case DT_STRUCT:
		case DT_UNION:
		case DT_ENUM:
		case DD_PTR:
		case DD_FUNC:
		case DD_ARRAY:
			iput(iget());
			continue;
			break;
		case DX_MEMBS:
			bput(n = iget());
			for ( ; n > 0; n-=1) {
				outdlab(1, bget());
			}
			break;
		case DX_NAME:
			iget();
			sget(id, NCSYMB);
			sput(id);
			break;
		default:
			cbotch("outdlab: %d", n);
		}
		break;
	}
}

#if	0			/* This routine is apparently unused. */
/*
 * Output a debug line record.
 */
outdlin(op)
{
	bput(TDLAB);
	bput(DC_LINE);
	iput(line);
	bput(op);
	bput(0);
	bput(DT_NONE);
	iput(0);
}
#endif

/*
 * Output a debug relocation record.
 * This 'n' is an index into the list of debug records written.
 */
outdloc(n)
{
	bput(TDLOC);
	iput(n);
}

/*
 * Finish up the code.
 * Some old outrel.c code is retained below for reference.
 */
outdone()
{
#if	0
	register SYM *sp;
	register int i;
#endif

	if (isvariant(VASM))
		return;

#if	0
	/*
	 * Make dlabel items for internally generated symbols.
	 */
	for (i = 0; i < NSHASH; i++) {
		for (sp = hash2[i]; sp != NULL; sp = sp->s_fp) {
			if (((sp->s_flag&S_GBL) != 0 || (sp->s_flag&S_DEF) == 0)
			 && ((sp->s_flag&S_PUT) == 0)) {
				bput(TDLAB);
				bput(DC_GREF);
				iput(0);
				sput(sp->s_id);
				bput(DT_NONE);
				iput(0);
			}
		}
	}
#endif

#if	EMUFIXUPS
	/*
	 * Put magic names into the symbol table
	 * if any 8087 code was generated.
	 */
	if (has8087) {
		wsp[0] = glookup("M:_WT",  0);
		wsp[1] = glookup("M:_WST", 0);
		wsp[2] = glookup("M:_WES", 0);
		wsp[3] = glookup("M:_WCS", 0);
		wsp[4] = glookup("M:_WSS", 0);
		wsp[5] = glookup("M:_WDS", 0);
	}
#endif
	bput(TEND);
}

/*
** Second pass routines.
** Read the temporary file and write the output.
*/
/*
 * Finish up.
 * Figure out the sizes and final values of everything.
 * Copy the code from the scratch file back to the output file.
 */
copycode()
{
	register int	op;
	register SYM	*sp;
	register int	i;
	register ADDRESS v;
	int		fixup;
	int		nd;
	int		nr;
	int		data;
	char		coment[30];
	long		debugdef;

	/*
	 * Assign base addresses to the compiler's logical segments, based on
	 * the compilation model and the settings of the VROM and VRAM flags.
	 */
	seg[SCODE].s_mseek = 0;
	v  = rup(seg[SCODE].s_dot);
	seg[SLINK].s_mseek = v;
	v += rup(seg[SLINK].s_dot);
	if ((isvariant(VSMALL))  || (isvariant(VRAM))) {
		code_size = v;
		v = 0;
	}
	seg[SPURE].s_mseek = v;
	v += rup(seg[SPURE].s_dot);
	if (notvariant(VROM) && notvariant(VRAM)) {
		if (isvariant(VSMALL))
			const_size = v;
		else
			code_size  = v;
		v = 0;
	}
	seg[SSTRN].s_mseek = v;
	v += rup(seg[SSTRN].s_dot);
	if (isvariant(VROM)) {
		if (isvariant(VSMALL))
			const_size = v;
		else
			code_size  = v;
		v = 0;
	}
	seg[SDATA].s_mseek = v;
	v += rup(seg[SDATA].s_dot);
	seg[SBSS].s_mseek  = v;
	bss_size  = rup(seg[SBSS].s_dot);
	data_size = v + bss_size;

	/*
	 * Put out the preamble.
	 */
	puttheadr();						/* THEADR */
	coment[0] = coment[1] = '\0';
	sprintf(&coment[2], "%s %s %s %s",
#ifdef vax
		"VAX",
#else
#ifdef UDI
		"UDI",
#else
#ifdef MSDOS
		"MS-DOS",
#else
		"COHERENT",
#endif
#endif
#endif
		"MWC86", VERSMWC,
		(isvariant(VSMALL)) ? "SMALL" : "LARGE");
	putrecord(COMENT, coment, strlen(&coment[2])+2);	/* COMENT */
	putlnames();						/* LNAMES */
	if (isvariant(VLARGE)) {
		putsegdef(PARA|CCON, code_size, 2, 4);		/* [1] */
		putsegdef(PARA|CCON, data_size, 3, 5);		/* [2] */
		if (VCSD)
			debugdef = putsegdef(BYTE|CCON, 0, 7, 6); /* [3] */
	} else {
		putsegdef(BYTE|CCON, code_size,  2, 2);		/* [1] */
		putsegdef(BYTE|CCON, const_size, 4, 4);		/* [2] */
		putsegdef(BYTE|CCON, data_size,  3, 3);		/* [3] */
		putsegdef(PARA|CSTACK,       0,  5, 5);		/* [4] */
		putsegdef(PARA|CMEM,         0,  6, 6);		/* [5] */
		if (VCSD)
			debugdef = putsegdef(BYTE|CCON, 0,  10, 9);	/* [6] */
		putrecord(GRPDEF, gdef1, sizeof(gdef1));	/* [1] */
		putrecord(GRPDEF, gdef2, sizeof(gdef2));	/* [2] */
	}
	putrecord(TYPDEF, typdef, sizeof(typdef));		/* TYPDEF */
	if (isvariant(VLARGE))
		putrecord(FIXUPP, lthred, sizeof(lthred));
	else
		putrecord(FIXUPP, sthred, sizeof(sthred));	/* Threads */
	putsymdef();					/* PUBDEF, EXTDEF */

	/*
	 * Copy out code.
	 */
	for (i=0; i<NSEG; ++i)
		seg[i].s_dot = seg[i].s_mseek;
	dotseg = SCODE;
	dot = seg[SCODE].s_dot;
	while ((op = bget()) != TEND) {
		switch (op) {

		case TENTER:
			notenuf();
			enter(bget());
			continue;
		case TDLAB:
			getdlab();
			continue;
		case TDLOC:
			getdloc();
			continue;
#if	0
/* See comment on outcb()/outdb() above. */
		case TCODE:
		case TDATA:
			if (isvariant(VSMALL))
				cbotch("code:data");
			enuf(2, 4);
			fixup = txtp - (txt+3);
			*txtp++ = 0;
			*txtp++ = 0;
			*relp++ = LOCAT|M|BASE|(fixup>>8);
			*relp++ = fixup;
			*relp++ = FTARGET|SECWAY|TSI;
			*relp++ = (op==TCODE) ? 1 : 2;
			dot += 2;
			continue;
#endif
		case TBASE:
			if (isvariant(VSMALL))
				cbotch("base");
			sp = pget();
			if ((sp->s_flag&S_DEF) != 0) {
				enuf(2, 4);
				fixup = txtp - (txt+3);
				*txtp++ = 0;
				*txtp++ = 0;
				*relp++ = LOCAT|M|BASE|(fixup>>8);
				*relp++ = fixup;
				*relp++ = FTARGET|SECWAY|TSI;
				*relp++ = getsegindex(sp->s_seg);
				dot += 2;
				continue;
			}
			nr = 4;
			if (sp->s_ref >= 128)
				++nr;
			enuf(2, nr);
			fixup = txtp - (txt+3);
			*txtp++ = 0;
			*txtp++ = 0;
			*relp++ = LOCAT|M|BASE|(fixup>>8);
			*relp++ = fixup;
			*relp++ = FTARGET|SECWAY|TEI;
			relp = setindex(relp, sp->s_ref);
			dot += 2;
			continue;
		}
		if ((op&TTYPE) == TBYTE) {
			nd = 1;
			data = bget();
		} else {
			nd = 2;
			data = iget();
		}
#if	EMUFIXUPS
		/*
		 * 8087 opcodes.
		 * Apply magic relocation for the emulator.
		 */
		if ((op&T8087) != 0) {
			sp = wsp[((op&T8087)-TWT)>>5];
			nr = 6;
			if (sp->s_ref >= 128)
				++nr;
			enuf(nd, nr);
			fixup = txtp - (txt+3);
			*txtp++ = data;
			if (nd != 1) {
				*txtp++ = data >> 8;
				fixup |= OFFSET << 8;	/* Locat */
			}
			fixup |= M << 8;		/* Seg rel */
			*relp++ = (fixup>>8) | LOCAT;	/* Not thread */
			*relp++ = fixup;
			*relp++ = FD8087;		/* Symbol based */
			*relp++ = 0;			/* Frame # */
			*relp++ = 0;
			relp = setindex(relp, sp->s_ref);
			dot += nd;
			continue;
		}
#endif
		/*
		 * Absolute.
		 */
		if ((op&(TSYM|TPCR)) == 0) {
			enuf(nd, 0);
			*txtp++ = data;
			if (nd != 1)
				*txtp++ = data >> 8;
			dot += nd;
			continue;
		}
		/*
		 * Absolute PC rel.
		 */
		if ((op&TSYM) == 0) {
			enuf(nd, 6);
			fixup = txtp - (txt+3);
			*txtp++ = 0;
			if (nd != 1) {
				*txtp++ = 0;
				fixup |= OFFSET << 8;
			}
			*relp++ = (fixup>>8) | LOCAT;	/* Not thread */
			*relp++ = fixup;
			*relp++ = FTARGET|TFN;		/* Absolute frame */
			*relp++ = 0;			/* Frame number */
			*relp++ = data;			/* Disp */
			*relp++ = data >> 8;
			dot += nd;
			continue;
		}
		/*
		 * Symbol based.
		 * I would like to always do this
		 * in the primary way. However, LINK-86
		 * doesn't do 3 byte offsets, so I cannot
		 * do a negative one.
		 */
		sp = pget();
		if ((sp->s_flag&S_DEF) != 0) {
			data += sp->s_value;
			/* Absolute */
			if ((op&TPCR)!=0 && sp->s_seg==dotseg) {
				enuf(nd, 0);
				data -= dot+nd;
				*txtp++ = data;
				if (nd != 1)
					*txtp++ = data >> 8;
				dot += nd;
				continue;
			}
			/* Segment relative */
			enuf(nd, 6);
			fixup = txtp - (txt+3);
			*txtp++ = 0;
			if (nd != 1) {
				*txtp++ = 0;
				fixup |= OFFSET << 8;	/* Loc */
			}
			if ((op&TPCR) == 0)
				fixup |= M << 8;	/* Seg rel */
			*relp++ = (fixup>>8) | LOCAT;	/* Not thread */
			*relp++ = fixup;
			fixup = F|FT0|TSI;		/* F code, seg ind */
			if (getsegindex(sp->s_seg) != 1)
				fixup |= FT1;		/* F data */
			*relp++ = fixup;
			*relp++ = getsegindex(sp->s_seg);
			*relp++ = data;			/* Disp */
			*relp++ = data >> 8;
			dot += nd;
			continue;
		}
		/*
		 * Symbol relative.
		 */
		nr = 4;
		if (sp->s_ref >= 128)			/* Two byte index */
			++nr;
		enuf(nd, nr);
		fixup = txtp - (txt+3);
		*txtp++ = data;
		if (nd != 1) {
			*txtp++ = data >> 8;
			fixup |= OFFSET << 8;		/* Loc */
		}
		if ((op&TPCR) == 0)
			fixup |= M << 8;		/* Seg rel */
		*relp++ = LOCAT|(fixup>>8);		/* Not THREAD */
		*relp++ = fixup;
		*relp++ = FTARGET|SECWAY|TEI;		/* Fix dat */
		relp = setindex(relp, sp->s_ref);
		dot += nd;
	}
	if (isvariant(VLINES))
		outbrace('}');
	if (notvariant(VLIB))
		dump();
	if (VCSD)
		oglobals();				/* Dump globals */
	enter(SDATA);					/* flush */
	/*
	 * If the size of the SBSS segment is nonzero,
	 * use an LIDATA item to get it zeroed when the program is run.
	 */
	if (bss_size != 0) {
		txtp = &txt[0];
		*txtp++ = (isvariant(VSMALL)) ? 3 : 2;	/* DATA */
		*txtp++ = seg[SBSS].s_mseek;		/* Offset */
		*txtp++ = seg[SBSS].s_mseek >> 8;
		*txtp++ = bss_size;			/* Length of loop */
		*txtp++ = bss_size >> 8;
		*txtp++ = 0;
		*txtp++ = 0;
		*txtp++ = 1;
		*txtp++ = 0;
		putrecord(LIDATA, txt, 9);		/* LIDATA */
	}
	putrecord(MODEND, modend, sizeof(modend));	/* MODEND */
#if VAXFMT
	vaxflush();
#endif
	if (VCSD) {
		if (fseek(ofp, debugdef, 0) == -1)
			cbotch("fixsegdef seek failed");
		if (isvariant(VLARGE))
			putsegdef(BYTE|CCON, seg[SDBG].s_dot, 7, 6);
		else
			putsegdef(BYTE|CCON, seg[SDBG].s_dot, 10, 9);
	}
}

/*
** Header writing routines.
*/
/*
 * Put out a THEADR item.
 * The name is just the module name that the compiler has been keeping.
 * It must be mapped into upper case before writing it to the file.
 */
puttheadr()
{
	register char *p1, *p2;
	register c;
	char b[40];

	p1 = module;
	p2 = &b[0];
	*p2++ = strlen(p1);
	while ((c = *p1++) != '\0') {
#if	0
		if (c>='a' && c<='z')
			c -= 'a'-'A';
#endif
		*p2++ = c;
	}
	putrecord(THEADR, b, p2-b);
}

/*
 * Write the list of names record.
 * For SMALL model, write the standard 'lnames' record:
 *	[1]  ""
 *	[2]  "CODE"
 *	[3]  "DATA"
 *	[4]  "CONST"
 *	[5]  "STACK"
 *	[6]  "MEMORY"
 *	[7]  "CGROUP"
 *	[8]  "DGROUP"
 *	[9]  "DEBUG"		(if -VCSD)
 *	[10] "module_DEBUG"	(if -VCSD)
 * For LARGE model, the names are:
 *	[1]  ""
 *	[2]  "module_CODE"
 *	[3]  "module_DATA"
 *	[4]  "CODE"
 *	[5]  "DATA"
 *	[6]  "DEBUG"		(if -VCSD)
 *	[7]  "module_DEBUG"	(if -VCSD)
 */
putlnames()
{
	register char *p1;
	char *movelname();
	char b[1 + 1+40+5 + 1+40+5 + 1+4 + 1+4 + 1+5 + 1+40+6];

	p1 = &b[0];
	*p1++ = 0;					/* "" */
	if (isvariant(VSMALL)) {
		p1 = movelname(p1, "CODE", 0);
		p1 = movelname(p1, "DATA", 0);
		p1 = movelname(p1, "CONST", 0);
		p1 = movelname(p1, "STACK", 0);
		p1 = movelname(p1, "MEMORY", 0);
		p1 = movelname(p1, "CGROUP", 0);
		p1 = movelname(p1, "DGROUP", 0);
	} else {
		p1 = movelname(p1, "CODE", 1);
		p1 = movelname(p1, "DATA", 1);
		p1 = movelname(p1, "CODE", 0);
		p1 = movelname(p1, "DATA", 0);
	}
	if (VCSD) {
		p1 = movelname(p1, "DEBUG", 0);
		p1 = movelname(p1, "DEBUG", 1);
	}
	putrecord(LNAMES, b, p1-b);
}

/*
 * If flag==0, move p2 to the supplied buffer p1.
 * If flag==1, move module_p2 to p1.
 * Used by putlnames().
 */
char *
movelname(p1, p2, flag)
register char *p1;
char *p2;
{
	register char *p3;
	register c;

	p3 = module;
	if (flag) {
		*p1++ = strlen(p3) + 1 + strlen(p2);	/* length of "module_p2" */
		while ((c = *p3++) != '\0') {		/* copy module name */
#if	0
			if (c>='a' && c<='z')
				c -= 'a'-'A';
#endif
			*p1++ = c;
		}
		*p1++ = '_';				/* append '_' */
	} else
		*p1++ = strlen(p2);
	p3 = p2;
	while ((c = *p3++) != '\0')			/* copy p2 */
		*p1++ = c;
	return (p1);
}

/*
 * This routine formats and outputs a SEGDEF item.
 * There is no checking for BIG segments (segments that are 64k in size).
 * The overlay index points to a null name.
 * Return the location of the first byte of the record.
 */
long
putsegdef(flag, size, segi, classi)
{
	long l;
	register char *bp;
	char b[6];

	l = ftell(ofp);
	bp = &b[0];
	*bp++ = flag;
	*bp++ = size;
	*bp++ = size >> 8;
	*bp++ = segi;
	*bp++ = classi;
	*bp++ = 1;
	putrecord(SEGDEF, b, 6);
	return(l);
}

/*
 * Sweep through the symbol table:
 *	1) Make symbols LSEG relative.
 *	2) Assign reference numbers.
 *	3) Output EXTDEF or PUBDEF.
 */
putsymdef()
{
	register SYM *sp;
	register int refnum;
	register int i;

	refnum = 1;
	for (i=0; i<NSHASH; ++i) {
		for (sp = hash2[i]; sp != NULL; sp = sp->s_fp ) {
			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 = 0;
				if ((sp->s_flag&S_DEF) != 0) {
					putpubdef(sp);
				} else {
					sp->s_ref = refnum++;
					putextdef(sp);
				}
			}
		}
	}
}

/*
 * Put out a PUBDEF item for symbol 'sp'.
 * All defs are tagged with the group
 * so that a FTARGET,EI fixup can determine the correct frame.
 */
putpubdef(sp)
register SYM *sp;
{
	register char *bp;
	char b[1+1+40+2+1];

	bp = &b[0];
	*bp++ = getgrpindex(sp->s_seg);
	*bp++ = getsegindex(sp->s_seg);
	bp = setsymid(bp, sp->s_id);
	*bp++ = sp->s_value;
	*bp++ = sp->s_value >> 8;
	*bp++ = 1;
	putrecord(PUBDEF, b, bp-b);
}

/*
 * Put out an EXTDEF item for symbol 'sp'.
 */
putextdef(sp)
register SYM *sp;
{
	register char *bp;
	char b[40+2];

	bp = setsymid(b, sp->s_id);
	*bp++ = 1;
	putrecord(EXTDEF, b, bp-b);
}

/*
 * Translate compiler segment codes
 * to OMF segment index value, using tables.
 * The table is selected by the model and the
 * setting of the VROM and VRAM variants.
 */
getsegindex(s)
register int	s;
{
	if (s > SBSS) {
		if (s == SDBG)
			return(isvariant(VSMALL) ? 6 : 3);
		else
			cbotch("getsegindex, seg=%d", s);
	}
	if (isvariant(VSMALL))
		return(  (isvariant(VRAM))  ? sramseg[s]
		       : (notvariant(VROM)) ? snonseg[s]
					    : sromseg[s]);
	else
		return(  (isvariant(VRAM))  ? lramseg[s]
		       : (notvariant(VROM)) ? lnonseg[s]
					    : lromseg[s]);
}

/*
 * Like getsegindex(), but returns a reloc-type segment name for CSD.
 */
segindex(s) register int s;
{
	register int seg;

	seg = getsegindex(s);		/* Map to output segment */
	if (isvariant(VSMALL)) {
		if (seg == 1)
			return(PURCODE);
		else if (seg == 2 || seg == 3)
			return(PURDATA);
	} else {
		if (seg == 1)
			return(PURCODE);
		else if (seg == 2)
			return(PURDATA);
	}
	cbotch("segindex, s=%x, seg=%x\n", s, seg);
}
	
/*
 * Translate compiler segment codes
 * to OMF group index value, using table and model.
 */
getgrpindex(s)
register int s;
{
 	return (isvariant(VSMALL) ? grpindex[s] : 0);
}

/*
** Debug information processors.
*/
/*
 * Read debug table item(s) into memory.
 */
getdlab()
{
	register struct dbgt *dp;
	static int refnum = 0;

	dp = getdbgt();

	/* This should be done in cc0 */

	if (isvariant(VLIB)) {
		switch (dp->d_class) {
			case DC_TYPE:
			case DC_STAG:
			case DC_UTAG:
			case DC_ETAG:
				return;
		}
	}
	if (dp->d_class == DC_LINE || dp->d_class == DC_LAB)
		dp->d_ref = refnum;

	refnum += 1; 
	if (dbase  == NULL)
		dbase = dp;
	if (dnext != NULL)
		dnext->d_dp = dp;
	dbrpt("enter", dp);
	while (dp->d_dp != NULL) {
		dp = dp->d_dp;
		dbrpt("enter", dp);
	}
	dnext = dp;
	if (dp->d_class == DC_FILE)
		outbrace('{');	
}

/*
 * Read in debug items translating into loader type syntax.
 * Member definitions are fetched recursively.
 * If a tag or type definition, the member definitions are appended to the
 * node surrounded by "{" and "}" nodes.
 * If not a tag definition, the member definitions are discarded.
 * In either case, the member types are appended to the type of the
 * parent node.
 */
#define	DSZ 512
struct dbgt *
getdbgt()
{
	register int n;
	register char *dptr;
	struct dbgt d;
	char data[DSZ];
	int value, width, offs;
	int typet, subt, membs;
	char *sdp;

	d.d_dp = NULL;
	d.d_ref = -1;
	d.d_flag = D_LCL;
	d.d_level = level;
	d.d_seg = LASTSEG;
	d.d_cseg = 0;
	d.d_value = 0;
	d.d_size = 0;
	width = membs = 0;

	/*
	 * Loop to read entire record:
	 *	class, optional value, name, type.
	 */
	dptr = data;
	for (typet = 0; ; typet += 1) {

		if (dptr >= data+DSZ) {
			dbrpt("1", &d);
			cbotch("getdbgt buffer");
		}

		n = bget();
		if (n < DX_MEMBS)
			value = iget() * NBPBYTE;
		else if (n < DC_SEX)
			;
		else {
			dline = iget();
			if (n < DC_AUTO)
				;
			else if (n < DC_MOS)
				value = iget();
			else {
				width = bget();
				offs = bget();
				value = iget();
			}
		}
		subt = 0;

		switch (n) {

		/*
		 * Classes: fetch values and set flags.
		 */
		case DC_SEX:
			d.d_flag |= D_NAM;
			goto setclass;

		case DC_GDEF:
		case DC_GREF:
			d.d_flag = D_GBL|D_NAM;
			goto setclass;

		case DC_ETAG:
			d.d_flag |= D_ENU;
			strcpy(dptr, "enum ");
			dptr += 5;
			goto tag;
		case DC_STAG:
			strcpy(dptr, "struct ");
			dptr += 7;
			goto tag;
		case DC_UTAG:
			strcpy(dptr, "union ");
			dptr += 6;
		case DC_TYPE:
			tag:
				d.d_flag = (level == 0) ? D_TAG|D_GBL
							: D_TAG|D_LCL;
				d.d_seg = TYPESYM;
				goto setclass;

		case DC_FILE:
			d.d_seg = PURCODE;
			goto setclass;

		case DC_AUTO:
			d.d_seg = L_STACK;
			d.d_value = value;
			goto setclass;

		case DC_SIN:
			d.d_flag |= D_LAB;
			goto setclass;

		case DC_LAB:
			goto setclass;

		case DC_REG:
			d.d_seg = L_REG;
			d.d_value = value;
			goto setclass;

		case DC_PREG:
			if (level == 0) {
				level++;
				outbrace('{');
			}
			d.d_seg = L_REG;
			d.d_value = value;
			goto setclass;

		case DC_MOE:
			d.d_seg = ABSLUTE;
			d.d_value = value;
			goto setclass;

		case DC_PAUTO:
 			if (level  == 0) {
				level++;
				outbrace('{');
			}
			d.d_seg = P_STACK;
			d.d_value = value;
			goto setclass;

		case DC_LINE:
			goto setclass;

		case DC_MOS:
		case DC_MOU:
			d.d_seg = FLD_OFF;
			d.d_value = value * NBPBYTE + offs;
			goto setclass;

		/*
		 * Set the class field, read the name;
		 * Lookup globals and statics.
		 */
		setclass:
			d.d_class = n;
			while (*dptr++ = bget())
				;
			if ((d.d_flag&(D_NAM|D_LAB)) != 0) {
				register SYM *sp;

				if ((d.d_flag&D_NAM) != 0)
					sp = glookup(data, 0);
				else
					sp = llookup(value, 0);
				if ((sp->s_flag&S_DEF) != 0) {
					d.d_cseg = sp->s_seg;
					d.d_seg = segindex(sp->s_seg);
					d.d_value = sp->s_value;
				}
#if COMMON
				else if (sp->s_value != 0) {
					d.d_seg = BLDATA|Cb;
					d.d_value = sp->s_value;
				}
#endif
				if ((d.d_flag&D_GBL) != 0)
					d.d_ref = sp->s_ref;
			}
			continue;

		/*
		 * Types: write type and prepare for trailing data.
		 * For files and lines, write a phony type.
		 */
		case DT_NONE:
			if (d.d_class == DC_FILE) {
				register char *p;

				*dptr++ = STRINGt;
				p = "source file";
				while (*dptr++ = *p++)
					;
			}
			if (d.d_class == DC_LINE) {
				*dptr++ = 6;	/* Line */
				*dptr++ = dline;
				*dptr++ = dline >> 8;
				*dptr++ = 0;	/* Column */
				*dptr++ = 0;	/* Flag */
				*dptr++ = 0;	/* Saved instruction */
				*dptr++ = 0;
			}
			break;

		case DT_CHAR:
		case DT_SHORT:
		case DT_INT:
		case DT_LONG:
			n = Integer;
			goto getwidth;

		case DT_UCHAR:
		case DT_USHORT:
		case DT_UINT:
		case DT_ULONG:
			n = Natural;
			goto getwidth;

		case DT_FLOAT:
		case DT_DOUBLE:
			n = Rational;
			goto settype;

		case DT_VOID:
			n = Void;
			goto settype;

		case DT_STRUCT:
			membs = n;
			n = Record;
			sdp = dptr;
			goto settype;

		case DT_UNION:
			membs = n;
			n = Union;
			sdp = dptr;
			goto settype;

		case DT_ENUM:
			d.d_flag |= D_ENU;
			membs = n;
			n = Natural;
			sdp = dptr;
			goto settype;

		getwidth:
			if (width)
				value = width;

		settype:
			*dptr++ = 1;
			*dptr++ = n;
			if (n != Void) {
				if (value == 0)
					*dptr++ = ANYt;
				else if (value <= 0377) {
					*dptr++ = 1;
					*dptr++ = value;
				} else {
					*dptr++ = 2;
					*dptr++ = value;
					*dptr++ = value >> 8;
				}
			}
			if (subt) {
				*dptr++ = TYPEt;
				continue;
			}
			if (membs) {
				--typet;
				continue;
			}
			break;

		/*
		 * Dimensions: as for types, but flag for subtypes.
		 */
		case DD_PTR:
			n = Pointer;
			++subt;
			goto settype;

		case DD_FUNC:
			n = Proc;
			++subt;
			goto settype;

		case DD_ARRAY:
			n = Array;
			++subt;
			goto settype;

		/*
		 * Trailing struct/union/enum data.
		 */
		case DX_NAME:
			dptr = sdp;
			*dptr++ = STRINGt;
			switch (membs) {
				case DT_STRUCT:
					strcpy(dptr, "struct ");
					dptr += 7;
					break;
				case DT_UNION:
					strcpy(dptr, "union ");
					dptr += 6;
					break;
				case DT_ENUM:
					strcpy(dptr, "enum ");
					dptr += 5;
			}
			while (*dptr++ = bget())
				;
			membs = 0;
			break;

		case DX_MEMBS:
			level += 1;
			dptr = getmembs(&d, data, dptr);
			level -= 1;
			membs = 0;
			break;

		default:
			cbotch("getdbgt: %d", n);
		}
		/*
		 * Terminate types.
		 */
		if (dptr + typet >= data + DSZ) {
			dbrpt("2", &d);
			cbotch("getdbgt buffer");
		}
		while (--typet >= 0)
			*dptr++ = 0;
		break;
	}

	/*
	 * Check level change.
	 */
	if (data[0] == '{') {
		if (level++ == 0) {
			d.d_level = level++;
			outbrace('{');
		}
	}
	else if (data[0] == '}')
		level -= 1;

	/*
	 * Copy into dynamic storage.
	 */
	d.d_size = dptr - data;
	return (newdbgt(&d, data));
}

/*
 * Enter a new output segment.
 */
enter(newseg)
register int newseg;
{
	if (dotseg == newseg)
		return;			/* already in newseg */
	notenuf();			/* flush */
	seg[dotseg].s_dot = dot;	/* save current dot */
	dotseg = newseg;		/* reset dotseg */
	dot = seg[dotseg].s_dot;	/* and dot */
}

/*
 * Read a debug relocation item and patch current 'dot'
 * into the appropriate debug/symbol table item.
 * If the debug item is '}' and level 2, then dump the batch of locals.
 * If the debug item is '}' and level 1, then dump the type definitions.
 */
getdloc()
{
	register struct dbgt *dp;
	register int ref;

	ref = iget();
	for (dp = dbase; ; dp = dp->d_dp) {
		if (dp == NULL)
			cbotch("getdloc: %d", ref);
		if ((dp->d_flag&D_GBL) != 0)
			continue;
		if (dp->d_ref == ref)
			break;
	}
	dp->d_cseg = dotseg;
	dp->d_seg = segindex(dotseg);
	dp->d_value = dot;

	dbrpt("reloc", dp);
	if (dp->d_data[0] == '}' && dp->d_level <= 2) {
		outbrace('}');
 		level--;
		dump();
	}
}

/*
 * Dump the locals and type definitions.
 */
dump()
{
	register struct dbgt *dp, **dpp;
	int saveseg;

	saveseg = dotseg;
	enter(SDBG);
	dpp = &dbase;
	dnext = NULL;
	while ((dp = *dpp) != NULL) {
		if ((dp->d_flag&D_LCL) != 0) {
			dbrpt("write", dp);
			osymbol(dp, -1);
			dp->d_flag &= ~D_LCL;
		}
		if ((dp->d_flag&D_GBL) == 0) {
			dbrpt("free", dp);
			*dpp = dp->d_dp;
			free(dp);
		} else {
			dbrpt("save", dp);
			dnext = dp;
			dpp = &dp->d_dp;
		}
	}
	enter(saveseg);
}

/*
 * Write out global symbol definitions and references.
 */
oglobals()
{
	register struct dbgt *dp, *dp1;

	enter(SDBG);
	for (dp = dbase; dp != NULL; dp = dp1) {
		dp1 = dp->d_dp;
		dbrpt("write", dp);
		if (dp->d_seg == TYPESYM || dp->d_seg == ABSLUTE)
			osymbol(dp, 0);
		else
			osymbol(dp, dp->d_ref);
		dbrpt("free", dp);
		free(dp);
	}
	notenuf();
}

/*
 * Write out a symbol to the symbol or debug table.
 * TYPESYM and ABSLUTE symbols have refnum 0.
 * Debug table symbols have negative refnums and may require relocation.
 */
osymbol(dp, refnum)
register struct dbgt *dp;
{
	register char *cp;
	unsigned char seg;
	int nd, nr, fixup, fixseg;

	/* Write scope/refnum or seg/value+relocation expression */
	seg = dp->d_seg;
	nd = 5 + dp->d_size;
	nr = 0;
#if 0
printf("osymbol(%s, %x) seg=%x cseg=%x nd=%x\n", dp->d_data, refnum, seg,
dp->d_cseg, nd);
#endif
	if (refnum >= 0) {
		if (seg == LASTSEG) {
			for (cp=dp->d_data; *cp++; )
				;		/* skip the name */
			seg = (*cp++ == 1 && *cp++ == Proc) ? PURCODE : PURDATA;
			fixseg = -1;		/* external fixup */
		} else
			fixseg = getsegindex(dp->d_cseg);
		if (seg != TYPESYM && seg != ABSLUTE)
			nr = (isvariant(VLARGE)) ? 10 : 6;
	} else if (refnum < 0) {
		if (seg < SUMMARY && seg != TYPESYM && seg != ABSLUTE) {
			nr = (isvariant(VLARGE)) ? 10 : 6;
			fixseg = getsegindex(dp->d_cseg);
		}
		else
	 		fixseg = 1;			/* CODE */
	}
	enuf(nd, nr);
	dot += nd;			/* bump dot */
	*txtp++ = seg;			/* reloc-style segment */
	if (fixseg == -1) {		/* extern fixup */
		if (isvariant(VLARGE)) {
			fixup = txtp - (txt+3);
			*relp++ = LOCAT|M|BASE|(fixup>>8);
			*relp++ = fixup;
			*relp++ = FTARGET|SECWAY|TEI;
			relp = setindex(relp, refnum);
		}
		*txtp++ = 0;
		*txtp++ = 0;
		fixup = txtp - (txt+3);
		*relp++ = LOCAT|M|OFFSET|(fixup>>8);
		*relp++ = fixup;
		*relp++ = FTARGET|SECWAY|TEI;
		relp = setindex(relp, refnum);
		*txtp++ = 0;
		*txtp++ = 0;
	} else {
		if (nr != 0 && isvariant(VLARGE)) {	/* segment fixup */
			fixup = txtp - (txt+3);
			*relp++ = LOCAT|M|BASE|(fixup>>8);
			*relp++ = fixup;
			*relp++ = FTARGET|SECWAY|TSI;
			*relp++ = fixseg;
		}
		*txtp++ = 0;
		*txtp++ = 0;			/* segment text */
		if (nr != 0) {			/* offset text and fixup */
			fixup = txtp - (txt+3);
			*relp++ = LOCAT|M|OFFSET|(fixup>>8);
			*relp++ = fixup;
			if (fixseg == 1)
				*relp++ = F|FT0|TSI;	/* fixup F code, seg index */
			else
				*relp++ = F|FT1|TSI;	/* fixup F data, seg index */
			*relp++ = fixseg;
			*relp++ = dp->d_value;
			*relp++ = dp->d_value >> 8;
			*txtp++ = 0;
			*txtp++ = 0;
		} else {
			*txtp++ = dp->d_value;
			*txtp++ = dp->d_value >> 8;	/* nonrelocated offset */
		}
	}

	/* Write name */
	cp = dp->d_data;
	nd = dp->d_size;
	do {
		*txtp++ = *cp;
		--nd;
	} while (*cp++);

	/* Type */
	while (--nd >= 0)
		*txtp++ = *cp++;	/* type */
}

/*
 * Read a list of members of a union/struct/enum.
 * If struct/union, append member types to caller's buffer.
 * If making a debug table:
 * If struct/union tag definition, bracket member definitions.
 * If enum tag, make member type into "enum tag".
 */
char *
getmembs(dp0, bb, bp)
struct dbgt *dp0;
char *bb;
register char *bp;
{
	int nmembs, n, istag, isenu, isgbl, isdbg;
	char *sbp;
	register struct dbgt *dp;
	struct dbgt **dpp;
	register char *p;
	static struct dbgt dbrace = {
		NULL,		/* d_dp		*/
		-1,		/* d_ref	*/
		DT_NONE,	/* d_class	*/
		D_LCL,		/* d_flag	*/
		0,		/* d_level	*/
		TYPESYM,	/* d_seg	*/
		0,		/* d_cseg	*/
		0,		/* d_value	*/
		3		/* d_size	*/
	};

	dp = dp0;
	nmembs = bget();
	istag = (dp->d_flag&D_TAG) != 0;
	isenu = (dp->d_flag&D_ENU) != 0;
	isgbl = (dp->d_flag&D_GBL) != 0;
	isdbg = VCSD;
	if (isenu) {
		sbp = bp;
		isenu = strlen(bb) + 1 + 1;
	}
	if ( ! isenu) {
#if	DO_STRUCT_TYPE
		/* Note that this blows up for nmembs > 255 anyway */
		*bp++ = 1;
		*bp++ = nmembs;
#else
		*bp++ = 1;
		*bp++ = 1;
		*bp++ = ANYt;
#endif
		dpp = &dp->d_dp;
		dp = *dpp = newdbgt(&dbrace, "{\0\0");
		if (isgbl)
			dp->d_flag ^= D_GBL|D_LCL;
	}
	dpp = &dp->d_dp;
	while (--nmembs >= 0) {
		/* Note that dp could be a tagless structure, ie a list */
		dp = *dpp = getdbgt();
		if (isgbl)
			dp->d_flag ^= D_GBL|D_LCL;
		n = dp->d_size;
		p = dp->d_data;
		if (isenu && istag && isdbg) {
			/* Enumerators eschew member lists */
			dp->d_size += isenu;
			dp = newdbgt(dp, dp->d_data);
			bp = dp->d_data;
			while (*bp++)
				;
			*bp++ = STRINGt;
			p = bb;
			while (*bp++ = *p++)
				;
			*bp++ = 0;
			free(*dpp);
			*dpp = dp;
			bp = sbp;
		}
#if	DO_STRUCT_TYPE
		if ( ! isenu) {
			do {
				--n;
			} while (*p++);
			*bp++ = TYPEt;
			if (bp + n >= bb + DSZ) {
				dbrpt("3", dp);
				cbotch("getdbgt buffer");
			}
			do {
				*bp++ = *p++;
			} while (--n > 0);
		}
#endif
		if (istag && isdbg)
			dpp = &dp->d_dp;
		else
			free(*dpp);
	}
	if ( ! isenu) {
		dp = *dpp = newdbgt(&dbrace, "}\0\0");
		dpp = &dp->d_dp;
		if (isgbl)
			dp->d_flag ^= D_GBL|D_LCL;
	}
	*dpp = NULL;
	return (bp);
}

struct dbgt *
newdbgt(dp, cp)
struct dbgt *dp;
register char *cp;
{
	register struct dbgt *ndp;
	register char *ncp;
	register int n;

	n = dp->d_size;
	if ((ndp = (struct dbgt *)malloc(sizeof(struct dbgt) + n)) == NULL)
		cnomem("newdbgt");
	*ndp = *dp;
	for (ncp = ndp->d_data; --n >= 0; *ncp++ = *cp++)
		;
	return (ndp);
}

/*
 * Output a debug brace.
 */
outbrace(c)
int c;
{
 	struct dbgt *dp;

	if ((dp = (struct dbgt *)calloc(1, sizeof(struct dbgt) + 10)) == NULL)
		cnomem("outbrace");
	dp->d_class = DC_LINE;
	dp->d_flag = D_LCL;
	dp->d_seg = segindex(SCODE);
	dp->d_value = ( dotseg == SCODE ? dot : seg[SCODE].s_dot);
	dp->d_size = 10;
	dp->d_data[0] = c;
	*(dp->d_data + 2) = 6;
	*(dp->d_data + 3) = dline;
	*(dp->d_data + 4) = dline >> 8;
	if (dnext != NULL)
		dnext->d_dp = dp;
	dnext = dp;
}

#if !TINY
_dbrpt(p, dp)
char *p;
register struct dbgt *dp;
{
	if (xflag > 5)
		printf("%5s: %-10s %2x %2d %2x %2x %2x %2x %04x %2x\n",
			p,
			dp->d_data,
			dp->d_class,
			dp->d_ref,
			dp->d_flag,
			dp->d_level,
			dp->d_seg,
			dp->d_cseg,
			dp->d_value,
			dp->d_size
		);
}

#endif

/*
** Low level record formatting.
*/
/*
 * Put OMF index i at cp and return updated cp.
 */
char *
setindex(cp, i)
register char *cp;
register unsigned i;
{
	if (i >= 128)
		*cp++ = (i >> 8) | 0x80;
	*cp++ = i;
	return (cp);
}

/*
 * This routine takes the name pointed to by 'cp' and
 * moves it into an OMF record. The 'bp' argument
 * is the OMF buffer pointer. The updated value
 * of 'bp' is returned.
 */
char *
setsymid(bp, cp)
register char *bp;
register char *cp;
{
	register c, n;

	if ((n=strlen(cp)) > 39) {
		cwarn("symbol \"%s\" truncated to 39 characters", cp);
		n = 39;
	}
	*bp++ = n;
	while (n--) {
#if	0
		if ((c = *cp++)>='a' && c<='z')
			c -= 'a'-'A';
		*bp++ = c;
#else
		*bp++ = *cp++;
#endif
	}
	return (bp);
}

/*
 * Put a record.
 * The 'type' argument is the record type.
 * The body of the record starts at 'p' and is
 * 'n' bytes long. The checksum is added.
 */
putrecord(type, p, n)
register char *p;
register n;
{
	checksum = 0;
	putbyte(type);
	putbyte(n+1);		/* +1 for the checksum */
	putbyte((n+1)>>8);
	while(n--)
		putbyte(*p++);
	putbyte(-checksum);
}

putbyte(b)
register b;
{
#if VAXFMT
	if (vaxptr >= &vaxbuf[NVDATA]) {
		vaxflush();
		vaxptr = vaxbuf;
	}
	*vaxptr++ = b;
#else
	bput(b);
#endif
	checksum += b;
}

/*
** Output buffering.
*/
/*
 * 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) {
		*txtp++ = getsegindex(dotseg);
		*txtp++ = dot;
		*txtp++ = dot >> 8;
	}
}

/*
 * Flush the buffer.
 */
notenuf()
{
	register n;

	if ((n = txtp-txt) > 3) {
		putrecord(LEDATA, txt, n);
		if ((n = relp-rel) != 0) {
			putrecord(FIXUPP, rel, n);
			relp = rel;
		}
	}
	txtp = txt;
}

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

#if VAXFMT
/*
 * Flush out a record on the VAX. The record is a standard,
 * RMS variable length record. This routine checks for no bytes
 * in the buffer, so it can be unconditionally called at the
 * end to flush the buffer out.
 * The record is padded out to NVDATA bytes with zeros. This
 * only happens on the last block; the data beyond the end
 * is zeroed.
 */
vaxflush()
{
	register int	n;

	if ((n = vaxptr-vaxbuf) != 0) {
		if (fwrite(vaxbuf, n, 1, ofp) != 1
		||  fflush(ofp) == EOF)
			cfatal("output write error");
	}
}
#endif

unix.superglobalmegacorp.com

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