File:  [MW Coherent from dump] / coherent / d / bin / cc / c / n2 / i8086 / outcsd.c
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	(512+3)			/* 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	CMEM	(0x01<<2)		/* C field, memory */
#define	CCON	(0x02<<2)		/* C field, concatenate */
#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	OFFSET	(0x01<<2)		/* Locat */
#define	BASE	(0x02<<2)		/* Locat */
#define	POINTER	(0x03<<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	FTARGET	(5<<4)			/* Frame: target */
#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	FT0	0x00			/* 0 */
#define	FT1	0x10			/* 1 */

/*
 * 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.
 */
typedef 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 */
} DBGT;
/* 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	islarge;		/* True iff isvariant(LARGE) */
static	int	isvcsd;			/* True iff -VCSD */
static	int	sx_code;		/* Segment index of SCODE */
static	int	sx_data;		/* Segment index of SDATA */
static	int	sx_debug;		/* Segment index of debug info */
static	char *	segtab;			/* Segment index conversion table */
static	char	txt[NTXT];		/* Text buffer */
static	char	rel[NREL];		/* Relocation buffer */
static	char *	txtp = txt;		/* Text pointer */
static	char *	relp = rel;		/* Relocation pointer */
static	DBGT *	dbase;			/* Root debug list item */
static	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	DBGT *	getdbgt();
extern	char *	getmembs();
extern	char *	malloc();
extern	char *	movename();
extern	DBGT *	newdbgt();
extern	long	putsegdef();
extern	char *	setindex();
extern	char *	setsymid();
extern	char *	strcpy();
extern	char *	strncpy();

/*
 * Logical name indices.
 * These must correspond to the order defined by the LNAMES
 * record written by putlnames().
 */
#define	LN_EMPTY	1	/* LARGE or SMALL ""	*/
#define	LN_L_M_CODE	2	/* LARGE "module_CODE"	*/
#define	LN_L_M_DATA	3	/* LARGE "module_DATA"	*/
#define	LN_L_CODE	4	/* LARGE "CODE"		*/
#define	LN_L_DATA	5	/* LARGE "DATA"		*/
#define	LN_L_DEBUG	6	/* LARGE "DEBUG"	*/
#define	LN_L_M_DEBUG	7	/* LARGE "module_DEBUG"	*/
#define	LN_S_CODE	2	/* SMALL "CODE"		*/
#define	LN_S_DATA	3	/* SMALL "DATA"		*/
#define	LN_S_CONST	4	/* SMALL "CONST"	*/
#define	LN_S_STACK	5	/* SMALL "STACK"	*/
#define	LN_S_MEMORY	6	/* SMALL "MEMORY"	*/
#define	LN_S_CGROUP	7	/* SMALL "CGROUP"	*/
#define	LN_S_DGROUP	8	/* SMALL "DGROUP"	*/
#define	LN_S_DEBUG	9	/* SMALL "DEBUG"	*/
#define	LN_S_M_DEBUG	10	/* SMALL "module_DEBUG"	*/

/*
 * Segment indices.
 * These must correspond to the order of the SEGDEF records
 * written by copycode().
 */
#define	SX_L_M_CODE	1	/* LARGE module_CODE	*/
#define	SX_L_M_DATA	2	/* LARGE module_DATA	*/
#define	SX_L_M_DEBUG	3	/* LARGE module_DEBUG	*/
#define	SX_S_CODE	1	/* SMALL CODE		*/
#define	SX_S_CONST	2	/* SMALL CONST		*/
#define	SX_S_DATA	3	/* SMALL DATA		*/
#define	SX_S_STACK	4	/* SMALL STACK		*/
#define	SX_S_MEMORY	5	/* SMALL MEMORY		*/
#define	SX_S_M_DEBUG	6	/* SMALL module_DEBUG	*/

/*
 * Group indices, SMALL model only.
 * These must correspond to the order of the GRPDEF records
 * written by copycode().
 */
#define	GX_CGROUP	1	/* CGROUP */
#define	GX_DGROUP	2	/* DGROUP */

/* Type index for NIL type. */
#define	TYPENIL		1

/*
 * getsegindex() uses the following tables,
 * 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.
 */
static	char	lnonseg[] = {
	SX_L_M_CODE,			/* SCODE => module_CODE */
	SX_L_M_CODE,			/* SLINK => module_CODE */
	SX_L_M_CODE,			/* SPURE => module_CODE */
	SX_L_M_DATA,			/* SSTRN => module_DATA */
	SX_L_M_DATA,			/* SDATA => module_DATA */
	SX_L_M_DATA			/* SBSS  => module_DATA */
};

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

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

static	char	snonseg[] = {
	SX_S_CODE,			/* SCODE => CODE */
	SX_S_CODE,			/* SLINK => CODE */
	SX_S_CONST,			/* SPURE => CONST */
	SX_S_DATA,			/* SSTRN => DATA */
	SX_S_DATA,			/* SDATA => DATA */
	SX_S_DATA			/* SBSS  => DATA */
};

static	char	sromseg[] = {
	SX_S_CODE,			/* SCODE => CODE */
	SX_S_CODE,			/* SLINK => CODE */
	SX_S_CONST,			/* SPURE => CONST */
	SX_S_CONST,			/* SSTRN => CONST */
	SX_S_DATA,			/* SDATA => DATA */
	SX_S_DATA			/* SBSS  => DATA */
};

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

/*
 * Same game, but for group index codes.
 * getgrpindex() uses this, in SMALL model only.
 */
static	char	grpindex[] = {
	GX_CGROUP,			/* SCODE => CGROUP */
	GX_CGROUP,			/* SLINK => CGROUP */
	GX_DGROUP,			/* SPURE => DGROUP */
	GX_DGROUP,			/* SSTRN => DGROUP */
	GX_DGROUP,			/* SDATA => DGROUP */
	GX_DGROUP			/* SBSS  => DGROUP */
};

/*
 * Some prefabricated OMF items.
 * These are just blasted out via calls to putrecord() in copycode().
 */
static	char	lthred[] = {
				0x40, SX_L_M_CODE,	/* frame0 -> module_CODE */
				0x41, SX_L_M_DATA	/* frame1 -> module_DATA */
			   };
static	char	gdef1[]  = {
				LN_S_CGROUP,
				0xFF, SX_S_CODE
			   };
static	char	gdef2[]  = {
				LN_S_DGROUP,
				0xFF, SX_S_CONST,
				0xFF, SX_S_DATA,
				0xFF, SX_S_STACK,
				0xFF, SX_S_MEMORY
			   };
static	char	sthred[] = {
				0x44, GX_CGROUP,	/* frame0 -> CGROUP */
				0x45, GX_DGROUP		/* frame1 -> DGROUP */
			   };
static	char	typdef[] = {	0, 0, 0x80 };		/* TYPDEF [1] NIL */
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
	/* Initialize global data which depends on variant. */
	islarge = isvariant(VLARGE);
	isvcsd = isvariant(VTYPES) || isvariant(VDSYMB);
	if (islarge) {
		sx_code  = SX_L_M_CODE;
		sx_data  = SX_L_M_DATA;
		sx_debug = SX_L_M_DEBUG;
		segtab =   isvariant(VROM) ? lromseg
			: notvariant(VRAM) ? lnonseg
					   : lramseg;
	} else {
		sx_code  = SX_S_CODE;
		sx_data  = SX_S_DATA;
		sx_debug = SX_S_M_DEBUG;
		segtab =   isvariant(VROM) ? sromseg
			: notvariant(VRAM) ? snonseg
					   : sramseg;
	}
}

/*
 * 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

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

/*
 * 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.
 */
outdone()
{
	if (isvariant(VASM))
		return;

#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;
	int		fixup;
	int		nd;
	int		data;
	long		debugdef;
	ADDRESS		code_size;
	ADDRESS		data_size;
	ADDRESS		const_size;
	ADDRESS		bss_size;

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

	/*
	 * Put out the preamble.
	 */
	putrecord(THEADR, txt, movename(txt, module, 0) - txt);	/* THEADR */
	txt[0] = txt[1] = '\0';
	sprintf(&txt[2], "%s %s %s %s",
#ifdef vax
		"VAX",
#else
#ifdef UDI
		"UDI",
#else
#ifdef MSDOS
		"MS-DOS",
#else
		"COHERENT",
#endif
#endif
#endif
		"MWC86", VERSMWC,
		(islarge) ? "LARGE" : "SMALL");
	putrecord(COMENT, txt, strlen(&txt[2])+2);	/* COMENT */
	putlnames();					/* LNAMES */
	/*
	 * The order of putsegdef() calls below must correspond to
 	 * the definitions of SX_... macros above.
	 * Debug segment sizes are fixed up ex post facto.
	 */
	if (islarge) {
/* [1] */	putsegdef(PARA|CCON, code_size, LN_L_M_CODE, LN_L_CODE);
/* [2] */	putsegdef(PARA|CCON, data_size, LN_L_M_DATA, LN_L_DATA);
		if (isvcsd)
/* [3] */		debugdef = putsegdef(BYTE|CCON, 0, LN_L_M_DEBUG, LN_L_DEBUG);
		putrecord(FIXUPP, lthred, sizeof(lthred));	/* Threads */
	} else {
/* [1] */	putsegdef(BYTE|CCON, code_size,  LN_S_CODE,   LN_S_CODE);
/* [2] */	putsegdef(BYTE|CCON, const_size, LN_S_CONST,  LN_S_CONST);
/* [3] */	putsegdef(BYTE|CCON, data_size,  LN_S_DATA,   LN_S_DATA);
/* [4] */	putsegdef(PARA|CSTACK,       0,  LN_S_STACK,  LN_S_STACK);
/* [5] */	putsegdef(PARA|CMEM,         0,  LN_S_MEMORY, LN_S_MEMORY);
		if (isvcsd)
/* [6] */		debugdef = putsegdef(BYTE|CCON, 0, LN_S_M_DEBUG, LN_S_DEBUG);
		/*
		 * The order of putrecord() calls below must correspond to
		 * the definitions of GX_... macros above.
		 */
/* [1] */	putrecord(GRPDEF, gdef1, sizeof(gdef1));
/* [2] */	putrecord(GRPDEF, gdef2, sizeof(gdef2));
		putrecord(FIXUPP, sthred, sizeof(sthred));	/* Threads */
	}
	putrecord(TYPDEF, typdef, sizeof(typdef));	/* TYPDEF */
	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;
		case TBASE:
			if (!islarge)
				cbotch("base");
			sp = pget();
			enuf(2, 5);
			fixup = txtp - (txt+3);
			*txtp++ = 0;
			*txtp++ = 0;
			dot += 2;
			*relp++ = LOCAT|M|BASE|(fixup>>8);
			*relp++ = fixup;
			if ((sp->s_flag&S_DEF) != 0) {
				*relp++ = FTARGET|SECWAY|TSI;
				*relp++ = getsegindex(sp->s_seg);
			} else {
				*relp++ = FTARGET|SECWAY|TEI;
				relp = setindex(relp, sp->s_ref);
			}
			continue;
		}
		if ((op&TTYPE) == TBYTE) {
			nd = 1;
			data = bget();
		} else {
			nd = 2;
			data = iget();
		}
		/* Assure enough space for text and relocation written below. */
#if	EMUFIXUPS
		enuf(nd, 7);
#else
		enuf(nd, 6);
#endif
		dot += nd;
		fixup = (txtp - (txt+3)) | (LOCAT << 8);

#if	EMUFIXUPS
		/*
		 * 8087 opcodes.
		 * Apply magic relocation for the emulator.
		 */
		if ((op&T8087) != 0) {
			sp = wsp[((op&T8087)-TWT)>>5];
			*txtp++ = data;
			if (nd != 1) {
				*txtp++ = data >> 8;
				fixup |= OFFSET << 8;	/* Locat */
			}
			fixup |= M << 8;		/* Seg rel */
			*relp++ = fixup>>8;
			*relp++ = fixup;
			*relp++ = FD8087;		/* Symbol based */
			*relp++ = 0;			/* Frame # */
			*relp++ = 0;
			relp = setindex(relp, sp->s_ref);
			continue;
		}
#endif
		/*
		 * Absolute.
		 */
		if ((op&(TSYM|TPCR)) == 0) {
			*txtp++ = data;
			if (nd != 1)
				*txtp++ = data >> 8;
			continue;
		}
		/*
		 * Absolute PC rel.
		 */
		if ((op&TSYM) == 0) {
			*txtp++ = 0;
			if (nd != 1) {
				*txtp++ = 0;
				fixup |= OFFSET << 8;
			}
			*relp++ = fixup>>8;
			*relp++ = fixup;
			*relp++ = FTARGET|TFN;		/* Absolute frame */
			*relp++ = 0;			/* Frame number */
			*relp++ = data;			/* Disp */
			*relp++ = data >> 8;
			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) {
				data -= dot;
				*txtp++ = data;
				if (nd != 1)
					*txtp++ = data >> 8;
				continue;
			}
			/* Segment relative */
			*txtp++ = 0;
			if (nd != 1) {
				*txtp++ = 0;
				fixup |= OFFSET << 8;	/* Loc */
			}
			if ((op&TPCR) == 0)
				fixup |= M << 8;	/* Seg rel */
			*relp++ = fixup>>8;
			*relp++ = fixup;
			if ((i = getsegindex(sp->s_seg)) == sx_code)
				*relp++ = F|FT0|TSI;	/* F code, seg ind */
			else
				*relp++ = F|FT1|TSI;	/* F data */
			*relp++ = i;
			*relp++ = data;			/* Disp */
			*relp++ = data >> 8;
			continue;
		}
		/*
		 * Symbol relative.
		 */
		*txtp++ = data;
		if (nd != 1) {
			*txtp++ = data >> 8;
			fixup |= OFFSET << 8;		/* Loc */
		}
		if ((op&TPCR) == 0)
			fixup |= M << 8;		/* Seg rel */
		*relp++ = fixup>>8;
		*relp++ = fixup;
		*relp++ = FTARGET|SECWAY|TEI;		/* Fix dat */
		relp = setindex(relp, sp->s_ref);
	}
	if (isvariant(VLINES))
		outbrace('}');
	if (notvariant(VLIB))
		dump();
	if (isvcsd)
		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++ = sx_data;
		*txtp++ = seg[SBSS].s_mseek;		/* Offset */
		*txtp++ = seg[SBSS].s_mseek >> 8;
		*txtp++ = bss_size;			/* Repeat count */
		*txtp++ = bss_size >> 8;
		*txtp++ = 0;				/* Block count */
		*txtp++ = 0;
		*txtp++ = 1;				/* Count */
		*txtp++ = 0;				/* Data */
		putrecord(LIDATA, txt, 9);		/* LIDATA */
	}
	putrecord(MODEND, modend, sizeof(modend));	/* MODEND */
#if	VAXFMT
	vaxflush();
#endif
	if (isvcsd) {
		if (fseek(ofp, debugdef, 0) == -1)
			cbotch("fixsegdef seek failed");
		if (islarge)
			putsegdef(BYTE|CCON, seg[SDBG].s_dot, LN_L_M_DEBUG, LN_L_DEBUG);
		else
			putsegdef(BYTE|CCON, seg[SDBG].s_dot, LN_S_M_DEBUG, LN_S_DEBUG);
	}
}

/*
 * Assign a base address to logical segment s.
 * Round up the segment size and bump dot.
 */
newseg(s)
register s;
{
	register ADDRESS n;

	if (((n = seg[s].s_dot)&1) == 1)
		seg[s].s_dot = ++n;	/* round up segment size to word */
	seg[s].s_mseek = dot;
	dot += n;
}

/*
** Header writing routines.
*/
/*
 * Write the list of names record.
 * The LN_... macros defined above must correspond to the order defined here.
 * For SMALL model, the names are:
 *	[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;

	p1 = &txt[0];
	*p1++ = 0;					/* "" */
	if (islarge) {
		p1 = movename(p1, "CODE", 1);
		p1 = movename(p1, "DATA", 1);
		p1 = movename(p1, "CODE", 0);
		p1 = movename(p1, "DATA", 0);
	} else {
		p1 = movename(p1, "CODE",   0);
		p1 = movename(p1, "DATA",   0);
		p1 = movename(p1, "CONST",  0);
		p1 = movename(p1, "STACK",  0);
		p1 = movename(p1, "MEMORY", 0);
		p1 = movename(p1, "CGROUP", 0);
		p1 = movename(p1, "DGROUP", 0);
	}
	if (isvcsd) {
		p1 = movename(p1, "DEBUG", 0);
		p1 = movename(p1, "DEBUG", 1);
	}
	putrecord(LNAMES, txt, p1-txt);
}

/*
 * If flag==0, move p2 to the supplied buffer p1.
 * If flag==1, move module_p2 to p1.
 */
char *
movename(p1, p2, flag)
register char *p1;
char *p2;
{
	register int n, m;

	n = strlen(p2);
	if (flag) {
		m = strlen(module);
		*p1++ = m + 1 + n;		/* length of "module_p2" */
		strcpy(p1, module);		/* copy module name */
		p1 += m;
		*p1++ = '_';			/* append '_' */
	} else
		*p1++ = n;			/* length of p2 */
	strcpy(p1, p2);				/* copy p2 */
	return(p1 + n);
}

/*
 * 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, seg, class)
{
	long l;
	register char *bp;

	l = ftell(ofp);
	bp = &txt[0];
	*bp++ = flag;
	*bp++ = size;
	*bp++ = size >> 8;
	*bp++ = seg;
	*bp++ = class;
	*bp = LN_EMPTY;
	putrecord(SEGDEF, txt, 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, *cp;

	cp = bp = &txt[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++ = TYPENIL;
	putrecord(PUBDEF, cp, bp-cp);
}

/*
 * Put out an EXTDEF item for symbol 'sp'.
 */
putextdef(sp)
SYM *sp;
{
	register char *bp, *cp;

	cp = &txt[0];
	bp = setsymid(cp, sp->s_id);
	*bp++ = TYPENIL;
	putrecord(EXTDEF, cp, bp-cp);
}

/*
 * 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(sx_debug);
		else
			cbotch("getsegindex, seg=%d", s);
	}
	return(segtab[s]);
}

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

	if ((seg = getsegindex(s)) == sx_code)
		return(PURCODE);
	else if (seg == sx_data || (!islarge && seg == SX_S_CONST))
		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 (islarge ? 0 : grpindex[s]);
}

/*
** Debug information processors.
*/
/*
 * Read debug table item(s) into memory.
 */
getdlab()
{
	register 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
DBGT *
getdbgt()
{
	register int n;
	register char *dptr;
	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 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 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 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 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;
	nr = 0;
#if	0
printf("osymbol(%s, %x) seg=%x cseg=%x d_size=%x\n",
dp->d_data, refnum, seg, dp->d_cseg, dp->d_size);
#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 = islarge ? 10 : 6;
	} else if (refnum < 0) {
		if (seg < SUMMARY && seg != TYPESYM && seg != ABSLUTE) {
			nr = islarge ? 10 : 6;
			fixseg = getsegindex(dp->d_cseg);
		}
		else
	 		fixseg = sx_code;
	}
	enuf(5, nr);
	dot += 5;			/* bump dot */
	*txtp++ = seg;			/* reloc-style segment */
	if (fixseg == -1) {		/* extern fixup */
		if (islarge) {
			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 && islarge) {	/* 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 == sx_code)
				*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;
	enuf(nd, 0);
	dot += nd;
	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)
DBGT *dp0;
char *bb;
register char *bp;
{
	int nmembs, n, istag, isenu, isgbl;
	char *sbp;
	register DBGT *dp;
	DBGT **dpp;
	register char *p;
	static 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;
	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 && isvcsd) {
			/* 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 && isvcsd)
			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);
}

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

	n = dp->d_size;
	if ((ndp = (DBGT *)malloc(sizeof(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;
{
 	DBGT *dp;

	if ((dp = (DBGT *)calloc(1, sizeof(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 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);
}

/*
 * Move the name pointed to by 'cp' into an OMF record.
 * The 'bp' argument is the OMF buffer pointer.
 * Return the updated value of 'bp'.
 */
char *
setsymid(bp, cp)
register char *bp;
char *cp;
{
	register n;

	if ((n=strlen(cp)) > 39) {
		cwarn("symbol \"%s\" truncated to 39 characters", cp);
		n = 39;
	}
	*bp++ = n;
	strncpy(bp, cp, n);
	return (bp + n);
}

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

/*
 * 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 appended.
 */
putrecord(type, p, n)
char *p;
int type, n;
{
	register int i, checksum;

	++n;				/* +1 for the checksum */
	checksum = type + n + (n>>8);	/* sum of first three bytes */
	putbyte(type);
	putbyte(n);
	putbyte(n>>8);
	--n;				/* restore actual byte count */
	while (n--) {
		putbyte(i = *p++);
		checksum += i;
	}
	putbyte(-checksum);
}

/*
** Output buffering.
*/
/*
 * Check to see if there is enough room in the text and relocation buffers
 * to hold 'nt' bytes of text and 'nr' bytes of relocation.
 * notenuf() flushes the buffers if necessary.
 */
enuf(nt, nr)
{
	if (txtp+nt>&txt[NTXT] || relp+nr>&rel[NREL]) {
		notenuf();
		if (nt > NTXT-3 || nr > NREL)
			cbotch("enuf(%d, %d)", nt, nr);
	}
	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;
}

#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.