|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.