You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1767 lines
45 KiB
1767 lines
45 KiB
/* asmemit.c -- microsoft 80x86 assembler
|
|
**
|
|
** microsoft (r) macro assembler
|
|
** copyright (c) microsoft corp 1986. all rights reserved
|
|
**
|
|
** randy nevin
|
|
**
|
|
** 10/90 - Quick conversion to 32 bit by Jeff Spencer
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <io.h>
|
|
#include <string.h>
|
|
#include "asm86.h"
|
|
#include "asmfcn.h"
|
|
|
|
#define LINBUFSIZE EMITBUFSIZE - 20 /* line # records can't as big */
|
|
|
|
#define OMFBYTE(c) *ebufpos++ = (unsigned char)(c)
|
|
#define FIXBYTE(c) *efixpos++ = (unsigned char)(c)
|
|
#define LINBYTE(c) *elinpos++ = (unsigned char)(c)
|
|
#define EBUFOPEN(c) (ebufpos+(c) <= emitbuf+EMITBUFSIZE)
|
|
#define EFIXOPEN(c) (efixpos+(c) < efixbuffer+EMITBUFSIZE)
|
|
#define ELINOPEN(c) (elinpos+(c) <= elinbuffer+LINBUFSIZE)
|
|
|
|
UCHAR emitbuf[EMITBUFSIZE];
|
|
UCHAR efixbuffer[EMITBUFSIZE];
|
|
UCHAR elinbuffer[LINBUFSIZE];
|
|
UCHAR *ebufpos = emitbuf;
|
|
UCHAR *efixpos = efixbuffer;
|
|
UCHAR *elinpos = elinbuffer;
|
|
UCHAR ehoffset = 0; /* number of bytes into segment index */
|
|
UCHAR emitrecordtype = 0;
|
|
OFFSET ecuroffset;
|
|
USHORT ecursegment;
|
|
long oOMFCur;
|
|
SHORT FixupOp = 0;
|
|
SHORT LedataOp = 0xA0;
|
|
|
|
USHORT linSegment;
|
|
UCHAR fLineUsed32;
|
|
SHORT fUnderScore;
|
|
UCHAR fIniter = TRUE;
|
|
UCHAR fNoMap; /* hack to disable fixup mapping for CV */
|
|
|
|
extern PFPOSTRUCT pFpoHead;
|
|
extern PFPOSTRUCT pFpoTail;
|
|
extern unsigned long numFpoRecords;
|
|
|
|
VOID CODESIZE edump( VOID );
|
|
VOID PASCAL CODESIZE emitoffset( OFFSET, SHORT );
|
|
|
|
/* The calls to the routines in this module appear in the following group
|
|
order. Ordering within a group is unspecified:
|
|
|
|
Group 1:
|
|
emodule (Pname)
|
|
|
|
Group 2:
|
|
emitsymbol (Psymb)
|
|
|
|
Group 3:
|
|
emitsegment (Psymb)
|
|
emitglobal (Psymb)
|
|
emitextern (Psymb)
|
|
|
|
Group 4:
|
|
emitcbyte (BYTE)
|
|
emitobject(pDSC)
|
|
emitcword (WORD)
|
|
emitdup (???)
|
|
|
|
Group 5:
|
|
emitdone (Psymb)
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*** emitsword - feed a word into the buffer
|
|
*
|
|
* emitsword (w);
|
|
*
|
|
* Entry w = word to feed into omf buffer
|
|
* Exit word placed in buffer low byte first
|
|
* Returns none
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitsword (
|
|
USHORT w
|
|
){
|
|
OMFBYTE(w);
|
|
OMFBYTE(w >> 8);
|
|
}
|
|
|
|
|
|
/* emitoff - write an offset, either 16 or 32 bits, depending upon
|
|
* use32. note conditional compilation trick with sizeof(OFFSET).
|
|
* with more cleverness, this could be a macro. -Hans */
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitoffset(
|
|
OFFSET off,
|
|
SHORT use32
|
|
){
|
|
emitsword((USHORT)off);
|
|
if (sizeof(OFFSET) > 2 && use32)
|
|
emitsword((USHORT)highWord(off));
|
|
}
|
|
|
|
/*** emitSymbol - output name string
|
|
*
|
|
* Entry
|
|
* pSY - pointer to symbol table entry to dump
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitSymbol(
|
|
SYMBOL FARSYM *pSY
|
|
){
|
|
if (pSY->attr & M_CDECL)
|
|
fUnderScore++;
|
|
|
|
if (pSY->lcnamp)
|
|
emitname ((NAME FAR *)pSY->lcnamp);
|
|
else
|
|
emitname (pSY->nampnt);
|
|
}
|
|
|
|
/*** emitname - write FAR name preceeded by length into omf buffer
|
|
*
|
|
* emitname (name);
|
|
*
|
|
* Entry name = FAR pointer to name string
|
|
* Exit length of name followed by name written to omf buffer
|
|
* Returns none
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitname (
|
|
NAME FAR *nam
|
|
){
|
|
char FAR *p;
|
|
|
|
OMFBYTE(STRFLEN ((char FAR *)nam->id)+fUnderScore);
|
|
|
|
if (fUnderScore) { /* leading _ for C language */
|
|
fUnderScore = 0;
|
|
OMFBYTE('_');
|
|
}
|
|
|
|
for (p = (char FAR *)nam->id; *p; p++)
|
|
OMFBYTE(*p);
|
|
}
|
|
|
|
|
|
/*** flushbuffer - write out linker record
|
|
*
|
|
* flushbuffer ();
|
|
*
|
|
* Entry ebufpos = next address in emitbuf
|
|
* emitbuf = data buffer
|
|
* emitrecordtype = type of omf data in buffer
|
|
* ehoffset = length of segment index data in buffer
|
|
* Exit data written to obj->fil if data in buffer
|
|
* buffer set empty (ebufpos = emitbuf)
|
|
* segment index length set to 0
|
|
* Returns none
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
flushbuffer ()
|
|
{
|
|
/* Don't put out an empty data record, but can do empty
|
|
* anything else */
|
|
|
|
if ((emitrecordtype&~1) != 0xA0 ||
|
|
(ebufpos - emitbuf) != ehoffset) /* RN */
|
|
ebuffer (emitrecordtype, ebufpos, emitbuf);
|
|
|
|
ebufpos = emitbuf;
|
|
ehoffset = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** flushfixup, flushline, write out fixup/line record
|
|
*
|
|
* flushfixup ();
|
|
*
|
|
* Entry efixbuffer = fixup buffer
|
|
* efixpos = address of next byte in fixup buffer
|
|
* Exit fixup buffer written to file if not empty
|
|
* fixup buffer set empty (efixpos = efixbuffer)
|
|
* Returns none
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
flushfixup ()
|
|
{
|
|
ebuffer (FixupOp, efixpos, efixbuffer);
|
|
FixupOp = 0;
|
|
efixpos = efixbuffer;
|
|
}
|
|
|
|
VOID PASCAL CODESIZE
|
|
flushline ()
|
|
{
|
|
USHORT recordT;
|
|
|
|
recordT = emitrecordtype;
|
|
|
|
ebuffer ( (USHORT)(fLineUsed32? 0x95: 0x94), elinpos, elinbuffer);
|
|
elinpos = elinbuffer;
|
|
emitrecordtype = (unsigned char)recordT;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** emitsetrecordtype - set record type and flush buffers if necessary
|
|
*
|
|
* emitsetrecordtype (t);
|
|
*
|
|
* Entry t = type of omf record
|
|
* Exit emit and fixup buffers flushed if t != current record type
|
|
* segment index written to buffer if data or dup omf record
|
|
* emit segment set to current segment
|
|
* emit offset set to offset within current segment
|
|
* Returns none
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitsetrecordtype (
|
|
UCHAR t
|
|
){
|
|
if (emitrecordtype && emitrecordtype != t) {
|
|
/* flush emit and fixup buffers if active and not of same type */
|
|
flushbuffer ();
|
|
flushfixup ();
|
|
switch(t)
|
|
{
|
|
case 0xA0:
|
|
case 0xA1: /* LEDATA or */
|
|
case 0xA2: /* LIDATA (dup) record */
|
|
case 0xA3:
|
|
if (pcsegment) {
|
|
|
|
/* create a new header */
|
|
ecursegment = pcsegment->symu.segmnt.segIndex;
|
|
ecuroffset = pcoffset;
|
|
emitsindex (pcsegment->symu.segmnt.segIndex);
|
|
|
|
/* if we are getting to the end of the buffer
|
|
* and its a 32 bit segment, we need to start
|
|
* using 32 bit offsets in the LEDATA header.
|
|
* -Hans */
|
|
|
|
if (wordsize == 4)
|
|
{
|
|
if (t>= 0xA2)
|
|
t = 0xA3;
|
|
/* there is a bug in the current linker--
|
|
* all ledata or lidata records within
|
|
* a module have to be either 16 or 32.
|
|
* comment out optimization until this
|
|
* is fixed */
|
|
else /* if (pcoffset>0x0ffffL-EMITBUFSIZE) */
|
|
LedataOp = t = 0xA1;
|
|
}
|
|
emitoffset((OFFSET)pcoffset, (SHORT)(t&1));
|
|
if (t&1)
|
|
ehoffset += 2; /* RN */
|
|
break;
|
|
}
|
|
else
|
|
errorc (E_ENS);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (t == 0xA4) {
|
|
t = 0xA1;
|
|
}
|
|
emitrecordtype = t;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** emitsindex - output 'index' of segment, external, etc.
|
|
*
|
|
* emitsindex (i);
|
|
*
|
|
* Entry i = index
|
|
* Exit index written to emit buffer
|
|
* ehoffset = 3 if single byte index
|
|
* ehoffset = 4 if double byte index
|
|
* Returns none
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitsindex (
|
|
register USHORT i
|
|
){
|
|
ehoffset = 3;
|
|
if (i >= 0x80) {
|
|
OMFBYTE((i >> 8) + 0x80);
|
|
ehoffset++;
|
|
}
|
|
OMFBYTE(i);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** emodule - output module name record
|
|
*
|
|
* emodule (pmodule);
|
|
*
|
|
* Entry pmodule = pointer to module name
|
|
* Exit module name written to obj->fil
|
|
* current emit segment and offset set to 0
|
|
* Returns none
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emodule (
|
|
NAME FAR *pmodule
|
|
){
|
|
char FAR *p;
|
|
|
|
emitsetrecordtype (0x80);
|
|
emitname (pmodule);
|
|
flushbuffer ();
|
|
|
|
if (fDosSeg) {
|
|
|
|
emitsetrecordtype (0x88);
|
|
emitsword((USHORT)(0x9E00 | 0x80)); /* nopurge + class = DOSSEG */
|
|
flushbuffer ();
|
|
}
|
|
|
|
if (codeview == CVSYMBOLS){
|
|
|
|
/* output speical comment record to handle symbol section */
|
|
|
|
emitsetrecordtype (0x88);
|
|
OMFBYTE(0);
|
|
emitsword(0x1a1);
|
|
emitsword('V'<< 8 | 'C');
|
|
flushbuffer ();
|
|
}
|
|
|
|
while (pLib) {
|
|
|
|
emitsetrecordtype (0x88);
|
|
emitsword((USHORT) (0x9F00 | 0x80)); /* nopurge + class = Library*/
|
|
|
|
for (p = (char FAR *)pLib->text; *p; p++)
|
|
OMFBYTE(*p);
|
|
|
|
flushbuffer ();
|
|
pLib = pLib->strnext;
|
|
}
|
|
|
|
ecuroffset = 0; /* initial for pass2 */
|
|
ecursegment = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** emitlname - put symbols into bufer to form 'lnames' record
|
|
*
|
|
* emitlname (psym);
|
|
*
|
|
* Entry psym = pointer to symbol structure
|
|
* Exit current record type set to LNAMES and buffer flushed if
|
|
* necessary. The name string is written to the emit buffer.
|
|
* Returns none
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitlname (
|
|
SYMBOL FARSYM *psym
|
|
){
|
|
emitsetrecordtype (0x96);
|
|
if (lnameIndex == 3) /* 1st time around */
|
|
OMFBYTE(0); /* output the NULL name */
|
|
|
|
if (!EBUFOPEN(STRFLEN (psym->nampnt->id) + 1)) {
|
|
flushbuffer ();
|
|
emitsetrecordtype (0x96);
|
|
}
|
|
emitSymbol(psym);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** emitsegment - output a segment definition record
|
|
*
|
|
* emitsegment (pseg);
|
|
*
|
|
* Entry pseg = pointer to segment name
|
|
* Exit record type set to SEGDEF and emit buffer flushed if necessary.
|
|
* SEGDEF record written to emit buffer
|
|
* Returns none
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitsegment (
|
|
SYMBOL FARSYM *pseg
|
|
){
|
|
UCHAR comb;
|
|
UCHAR algn;
|
|
SHORT use32=0;
|
|
|
|
/* use32 is whether to put out 16 or 32 bit offsets. it
|
|
* only works if segmnt.use32 is enabled. the D bit
|
|
* is keyed off segmnt.use32 -Hans */
|
|
|
|
if (sizeof(OFFSET)>2 &&
|
|
(pseg->symu.segmnt.use32 > 2) &&
|
|
pseg->symu.segmnt.seglen > 0xffffL)
|
|
use32 = 1;
|
|
|
|
emitsetrecordtype ((UCHAR)(0x98+use32)); /* SEGDEF */
|
|
|
|
algn = pseg->symu.segmnt.align;
|
|
comb = pseg->symu.segmnt.combine;
|
|
|
|
#ifdef V386
|
|
if (!use32 && pseg->symu.segmnt.seglen == 0x10000L) /* add 'big' bit? */
|
|
if (pseg->symu.segmnt.use32 > 2)
|
|
OMFBYTE((algn<<5) + (comb<<2) + 3); /* add 'D' bit */
|
|
else
|
|
OMFBYTE((algn<<5) + (comb<<2) + 2);
|
|
else
|
|
#endif
|
|
if (pseg->symu.segmnt.use32 > 2)
|
|
OMFBYTE((algn<<5) + (comb<<2) + 1); /* add 'D' bit */
|
|
else
|
|
OMFBYTE((algn<<5) + (comb<<2));
|
|
|
|
if (algn == 0 || algn == (UCHAR)-1) {
|
|
/* segment number of seg */
|
|
emitsword ((USHORT)pseg->symu.segmnt.locate);
|
|
OMFBYTE(0);
|
|
}
|
|
emitoffset(pseg->symu.segmnt.seglen, use32);
|
|
|
|
emitsindex (pseg->symu.segmnt.lnameIndex);
|
|
pseg->symu.segmnt.segIndex = segmentnum++;
|
|
|
|
/* seg, class number */
|
|
if (!pseg->symu.segmnt.classptr) /* Use blank name */
|
|
emitsindex (1);
|
|
else
|
|
emitsindex((USHORT)((pseg->symu.segmnt.classptr->symkind == SEGMENT) ?
|
|
pseg->symu.segmnt.classptr->symu.segmnt.lnameIndex:
|
|
pseg->symu.segmnt.classptr->symu.ext.extIndex));
|
|
|
|
emitsindex (1);
|
|
flushbuffer ();
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** emitgroup - output a group record
|
|
*
|
|
* emitgroup (pgrp);
|
|
*
|
|
* Entry pgrp = pointer to group name
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitgroup (
|
|
SYMBOL FARSYM *pgrp
|
|
){
|
|
SYMBOL FARSYM *pseg;
|
|
|
|
emitsetrecordtype (0x9A);
|
|
|
|
emitsindex (pgrp->symu.grupe.groupIndex);
|
|
pgrp->symu.grupe.groupIndex = groupnum++;
|
|
|
|
pseg = pgrp->symu.grupe.segptr;
|
|
while (pseg) {
|
|
if (pseg->symu.segmnt.segIndex){
|
|
|
|
OMFBYTE(((pseg->attr == XTERN)? 0xFE: 0xFF));
|
|
emitsindex (pseg->symu.segmnt.segIndex);
|
|
}
|
|
pseg = pseg->symu.segmnt.nxtseg;
|
|
}
|
|
flushbuffer ();
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** emitglobal - output a global declaration
|
|
*
|
|
* emitglobal (pglob);
|
|
*
|
|
* Entry pglob = pointer to global name
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitglobal (
|
|
SYMBOL FARSYM *pglob
|
|
){
|
|
static SHORT gIndexCur = -1, sIndexCur = -1;
|
|
register SHORT gIndex, sIndex, cbNeeded;
|
|
OFFSET pubvalue;
|
|
SHORT use32 = 0x90;
|
|
|
|
pubvalue = pglob->offset;
|
|
if ((unsigned long)pubvalue >= 0x10000l)
|
|
use32 = 0x91;
|
|
|
|
/* A public EQU can be negative, so must adjust value */
|
|
/* this is happening because masm keeps numbers
|
|
* in 17/33 bit sign magnitude representation */
|
|
|
|
if ((pglob->symkind == EQU) && pglob->symu.equ.equrec.expr.esign)
|
|
pubvalue = (short)(((use32==0x91? 0xffffffffl : 65535) - pglob->offset) + 1);
|
|
|
|
|
|
/* Match Intel action, If a global is code, it should
|
|
belong to the group of the CS assume at the time of
|
|
definition, if there is one */
|
|
|
|
/* Output group index for data labels too */
|
|
|
|
sIndex = gIndex = 0;
|
|
|
|
if (((1 << pglob->symkind) & (M_PROC | M_CLABEL))
|
|
&& pglob->symu.clabel.csassume
|
|
&& pglob->symu.clabel.csassume->symkind == GROUP
|
|
&& pglob->symsegptr && pglob->symsegptr->symu.segmnt.grouptr)
|
|
|
|
gIndex = pglob->symu.clabel.csassume->symu.grupe.groupIndex;
|
|
|
|
|
|
if (pglob->symsegptr)
|
|
sIndex = pglob->symsegptr->symu.segmnt.segIndex;
|
|
|
|
cbNeeded = STRFLEN ((char FAR *)pglob->nampnt->id) + 13;
|
|
|
|
if (gIndex != gIndexCur ||
|
|
sIndex != sIndexCur ||
|
|
emitrecordtype != use32 ||
|
|
!EBUFOPEN(cbNeeded)) { /* start a new record */
|
|
|
|
flushbuffer();
|
|
emitsetrecordtype ((UCHAR)use32);
|
|
|
|
gIndexCur = gIndex;
|
|
sIndexCur = sIndex;
|
|
|
|
emitsindex (gIndexCur);
|
|
emitsindex (sIndexCur);
|
|
|
|
if (sIndex == 0) /* absolutes require a 0 frame # */
|
|
emitsword (sIndex);
|
|
}
|
|
|
|
emitSymbol(pglob);
|
|
|
|
emitoffset(pubvalue, (SHORT)(use32&1));
|
|
if (codeview == CVSYMBOLS) {
|
|
|
|
if (pglob->symkind == EQU) /* type not stored */
|
|
|
|
emitsindex(typeFet(pglob->symtype));
|
|
else
|
|
emitsindex (pglob->symu.clabel.type);
|
|
}
|
|
else
|
|
emitsindex(0); /* untyped */
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** emitextern - emit an external
|
|
*
|
|
* emitextern (psym)
|
|
*
|
|
* Entry *psym = symbol entry for external
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitextern (
|
|
SYMBOL FARSYM *psym
|
|
){
|
|
USHORT recType;
|
|
|
|
recType = 0x8c;
|
|
|
|
if (psym->symkind == EQU){
|
|
|
|
/* this an extrn lab:abs definition, which is allocated as
|
|
* an EQU record which doesn't have space for a index so
|
|
* it stored in the unused length field */
|
|
|
|
psym->length = externnum++;
|
|
}
|
|
else {
|
|
psym->symu.ext.extIndex = externnum++;
|
|
|
|
if (psym->symu.ext.commFlag)
|
|
recType = 0xb0;
|
|
}
|
|
|
|
fKillPass1 |= pass2;
|
|
|
|
emitsetrecordtype ((UCHAR)recType);
|
|
|
|
if (!EBUFOPEN(STRFLEN (psym->nampnt->id) + 9)) {
|
|
flushbuffer ();
|
|
emitsetrecordtype ((UCHAR)recType);
|
|
}
|
|
|
|
emitSymbol(psym);
|
|
|
|
if (codeview == CVSYMBOLS)
|
|
|
|
emitsindex(typeFet(psym->symtype));
|
|
else
|
|
OMFBYTE(0);
|
|
|
|
if (recType == 0xb0) { /* output commdef variate */
|
|
|
|
if (psym->symu.ext.commFlag == 1) { /* near item */
|
|
|
|
OMFBYTE(0x62);
|
|
/* size of field */
|
|
OMFBYTE(0x81);
|
|
emitsword((USHORT)(psym->symu.ext.length * psym->symtype));
|
|
}
|
|
else {
|
|
OMFBYTE(0x61); /* far item */
|
|
|
|
OMFBYTE(0x84); /* # of elements */
|
|
emitsword((USHORT)psym->symu.ext.length);
|
|
OMFBYTE(psym->symu.ext.length >> 16);
|
|
|
|
OMFBYTE(0x81); /* element size */
|
|
emitsword(psym->symtype);
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*** emitfltfix - emit fixup for floating point
|
|
*
|
|
* emitfltfix (group, extidx);
|
|
*
|
|
* Entry
|
|
* *extidx = external id (0 if not assigned)
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitfltfix (
|
|
USHORT group,
|
|
USHORT item,
|
|
USHORT *extidx
|
|
){
|
|
register SHORT i;
|
|
|
|
if (*extidx == 0) {
|
|
/* Must define it */
|
|
if (!moduleflag)
|
|
dumpname ();
|
|
/* All fixups are FxyRQQ */
|
|
*extidx = externnum++;
|
|
if (!EBUFOPEN(7))
|
|
flushbuffer ();
|
|
emitsetrecordtype (0x8C);
|
|
/* Name length */
|
|
OMFBYTE(6);
|
|
OMFBYTE('F');
|
|
OMFBYTE(group); /* Group I or J */
|
|
OMFBYTE(item); /* Item D, W, E, C, S, A */
|
|
OMFBYTE('R');
|
|
OMFBYTE('Q');
|
|
OMFBYTE('Q');
|
|
OMFBYTE(0);
|
|
}
|
|
if (pass2) { /* Must put out a extern ref */
|
|
if (!EFIXOPEN(5))
|
|
emitdumpdata ( (UCHAR)LedataOp);
|
|
emitsetrecordtype ( (UCHAR) LedataOp);
|
|
|
|
FixupOp = 0x9C + (LedataOp & 1);
|
|
|
|
/* output location */
|
|
i = (SHORT)(ebufpos - emitbuf - ehoffset);
|
|
FIXBYTE(0xC4 + (i >> 8));
|
|
FIXBYTE(i);
|
|
FIXBYTE(0x46);
|
|
|
|
if (*extidx >= 0x80) /* Output 2 byte link # */
|
|
FIXBYTE ((UCHAR)((*extidx >> 8) + 0x80));
|
|
|
|
FIXBYTE(*extidx);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*** emitline - output a line number offset pair
|
|
*
|
|
* emitline(pcOffset)
|
|
*
|
|
* Entry pcoffset: code offset to output
|
|
* src->line: for the current line number
|
|
* Exit none
|
|
*/
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitline()
|
|
{
|
|
static UCHAR fCurrent32;
|
|
|
|
if (codeview < CVLINE || !pass2 || !objing || !pcsegment)
|
|
return;
|
|
|
|
if (macrolevel == 0 ||
|
|
!fPutFirstOp) {
|
|
|
|
fCurrent32 = (emitrecordtype == 0xA1);
|
|
|
|
if (linSegment != pcsegment->symu.segmnt.segIndex ||
|
|
! ELINOPEN(2 + wordsize) ||
|
|
fLineUsed32 != fCurrent32 ) {
|
|
|
|
flushline();
|
|
|
|
/* Start a new line # segment */
|
|
|
|
linSegment = pcsegment->symu.segmnt.segIndex;
|
|
fLineUsed32 = fCurrent32;
|
|
|
|
/* start record with group index and segment index */
|
|
|
|
LINBYTE(0); /* no group */
|
|
|
|
if (linSegment >= 0x80) /* Output 2 byte link # */
|
|
LINBYTE ((UCHAR)((linSegment >> 8) + 0x80));
|
|
|
|
LINBYTE(linSegment);
|
|
}
|
|
|
|
LINBYTE(pFCBCur->line); /* First line # */
|
|
LINBYTE(pFCBCur->line >> 8);
|
|
|
|
LINBYTE(pcoffset); /* then offset */
|
|
LINBYTE(pcoffset >> 8);
|
|
|
|
if (fLineUsed32) { /* 32 bit offset for large segments */
|
|
|
|
LINBYTE(highWord(pcoffset));
|
|
LINBYTE(highWord(pcoffset) >> 8);
|
|
}
|
|
}
|
|
if (macrolevel != 0)
|
|
fPutFirstOp = TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*** fixroom - check for space in fix buffer
|
|
*
|
|
* flag = fixroom (n);
|
|
*
|
|
* Entry n = number of bytes to insert in buffer
|
|
* Exit none
|
|
* Returns TRUE if n bytes will fit in buffer
|
|
* FALSE if n bytes will not fit in buffer
|
|
*/
|
|
|
|
|
|
UCHAR PASCAL CODESIZE
|
|
fixroom (
|
|
register UCHAR n
|
|
){
|
|
return (EFIXOPEN(n));
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** emitcleanq - check for buffer cleaning
|
|
*
|
|
* flag = emitcleanq (n);
|
|
*
|
|
* Entry n = number of bytes to insert in buffer
|
|
* Exit E_ENS error message issued if pcsegment is null
|
|
* Returns TRUE if
|
|
*/
|
|
|
|
|
|
UCHAR PASCAL CODESIZE
|
|
emitcleanq (
|
|
UCHAR n
|
|
){
|
|
if (!pcsegment)
|
|
|
|
errorc (E_ENS);
|
|
else
|
|
return (ecursegment != pcsegment->symu.segmnt.segIndex ||
|
|
pcoffset != ecuroffset ||
|
|
!EBUFOPEN(n));
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** emitdumpdata - clean data buffer and set up for data record
|
|
*
|
|
* emitdumpdata (recordnum);
|
|
*
|
|
* Entry recordnum = record type
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitdumpdata (
|
|
UCHAR recordnum
|
|
){
|
|
flushbuffer ();
|
|
/* force dump of buffer */
|
|
emitrecordtype = 0xFF;
|
|
emitsetrecordtype (recordnum);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** emitcbyte - emit constant byte into segment
|
|
*
|
|
* emitcbyte (b)
|
|
*
|
|
* Entry b = byte
|
|
* pcsegment = pointer to segment symbol entry
|
|
* pcoffset = offset into segment
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitcbyte (
|
|
UCHAR b
|
|
){
|
|
/* if the segment is changed or the offset is not current or there
|
|
is no room in the buffer then flush buffer and start over */
|
|
|
|
if (emitcleanq (1))
|
|
emitdumpdata ((UCHAR)LedataOp);
|
|
|
|
emitsetrecordtype ((UCHAR)LedataOp);
|
|
OMFBYTE(b);
|
|
ecuroffset++;
|
|
}
|
|
|
|
|
|
|
|
/*** emitcword - place a constant word into data record
|
|
*
|
|
* emitcword (w);
|
|
*
|
|
* Entry w = word
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitcword (
|
|
OFFSET w
|
|
){
|
|
if (emitcleanq (2))
|
|
emitdumpdata ((UCHAR)LedataOp);
|
|
|
|
emitsetrecordtype ((UCHAR)LedataOp);
|
|
emitsword ((USHORT)w);
|
|
ecuroffset += 2;
|
|
}
|
|
|
|
/*** emitcdword - place a constant word into data record
|
|
*
|
|
* emitcword (w);
|
|
*
|
|
* Entry w = word
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
VOID PASCAL CODESIZE
|
|
emitcdword (
|
|
OFFSET w
|
|
){
|
|
if (emitcleanq (4))
|
|
emitdumpdata ((UCHAR)LedataOp);
|
|
|
|
emitsetrecordtype ((UCHAR)LedataOp);
|
|
emitsword ((USHORT)w);
|
|
emitsword (highWord(w));
|
|
ecuroffset += 4;
|
|
}
|
|
|
|
|
|
|
|
/*** emitlong - emit a long constant
|
|
*
|
|
* emitlong (pdsc);
|
|
*
|
|
* Entry *pdsc = duprecord
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitlong (
|
|
struct duprec FARSYM *pdsc
|
|
){
|
|
UCHAR *cp;
|
|
OFFSET tmpstart;
|
|
OFFSET tmpcurr;
|
|
OFFSET tmplimit;
|
|
|
|
tmpstart = pcoffset;
|
|
cp = pdsc->duptype.duplong.ldata;
|
|
tmplimit = (pcoffset + pdsc->duptype.duplong.llen) - 1;
|
|
for (tmpcurr = tmpstart; tmpcurr <= tmplimit; ++tmpcurr) {
|
|
pcoffset = tmpcurr;
|
|
emitcbyte ((UCHAR)*cp++);
|
|
}
|
|
pcoffset = tmpstart;
|
|
}
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitnop ()
|
|
{
|
|
errorc(E_NOP);
|
|
emitopcode(0x90);
|
|
}
|
|
|
|
|
|
|
|
/*** emitobject - emit object in dup or iter record to OMF stream
|
|
*
|
|
* emitobject (pdesc);
|
|
*
|
|
* Entry *pdesc = parse stack entry
|
|
* Global - fInter -> FALSE if in iterated DUP
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitobject (
|
|
register struct psop *pso
|
|
){
|
|
register SHORT i;
|
|
|
|
if (!pcsegment) {
|
|
errorc (E_ENS);
|
|
return;
|
|
}
|
|
mapFixup(pso);
|
|
|
|
if (fIniter) {
|
|
|
|
i = LedataOp;
|
|
if (wordsize == 4 || pso->fixtype >= F32POINTER)
|
|
i |= 1;
|
|
|
|
emitsetrecordtype ((UCHAR)i);
|
|
}
|
|
|
|
/* Data or DUP record */
|
|
if (pso->fixtype == FCONSTANT) {
|
|
|
|
if (!fIniter) {
|
|
if (pso->dsize == 1)
|
|
OMFBYTE(pso->doffset);
|
|
else if (pso->dsize == 2)
|
|
emitsword ((USHORT)pso->doffset);
|
|
else
|
|
for (i = pso->dsize; i; i--)
|
|
OMFBYTE(0);
|
|
}
|
|
else switch(pso->dsize) {
|
|
|
|
case 1:
|
|
emitcbyte ((UCHAR)pso->doffset);
|
|
break;
|
|
case 2:
|
|
emit2:
|
|
emitcword (pso->doffset);
|
|
break;
|
|
case 4:
|
|
emit4:
|
|
emitcdword (pso->doffset);
|
|
break;
|
|
default:
|
|
/* the indeterminate case had been set up
|
|
by emit2byte as 2. we are now leaving
|
|
it as zero and doing the mapping here. */
|
|
|
|
if (wordsize==4)
|
|
goto emit4;
|
|
else
|
|
goto emit2;
|
|
}
|
|
}
|
|
else
|
|
emitfixup (pso);
|
|
}
|
|
|
|
|
|
|
|
/*** emitfixup - emit fixup data into fixup buffer
|
|
*
|
|
* emitfixup (pso)
|
|
*
|
|
* Entry PSO for object
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitfixup (
|
|
register struct psop *pso
|
|
){
|
|
UCHAR fixtype;
|
|
USHORT dlen; /* length of operand */
|
|
UCHAR flen; /* length of fixup */
|
|
SYMBOL FARSYM *pframe;
|
|
SYMBOL FARSYM *ptarget;
|
|
register USHORT tmp;
|
|
SHORT i;
|
|
|
|
fixtype = fixvalues[pso->fixtype];
|
|
|
|
emitgetspec (&pframe, &ptarget, pso);
|
|
|
|
/* magic numbers for omf types. */
|
|
|
|
dlen = pso->dsize;
|
|
|
|
if (ptarget){
|
|
if ((M_XTERN & ptarget->attr) &&
|
|
!pframe && (fixtype == 2 || fixtype == 3))
|
|
pframe = ptarget;
|
|
}
|
|
else
|
|
return;
|
|
|
|
flen = 7;
|
|
if (pso->doffset) /* target displacement */
|
|
flen += 2 + ((emitrecordtype&1) << 1);
|
|
|
|
/* make sure that we have enough room in the various buffers */
|
|
if (fIniter)
|
|
if (emitcleanq ((UCHAR)dlen) || !EFIXOPEN(flen))
|
|
emitdumpdata ((UCHAR)(LedataOp +2 - 2 * fIniter)); /* RN */
|
|
|
|
/* set fixup type--32 or 16 */
|
|
if (emitrecordtype&1)
|
|
{
|
|
if (FixupOp == 0x9C)
|
|
errorc(E_PHE); /* is there a better message? */
|
|
FixupOp = 0x9D;
|
|
}
|
|
else
|
|
{
|
|
if (FixupOp == 0x9D)
|
|
errorc(E_PHE); /* is there a better message? */
|
|
FixupOp = 0x9C;
|
|
}
|
|
/* build high byte of location */
|
|
tmp = 0x80 + (fixtype << 2);
|
|
if (!(M_SHRT & pso->dtype)) /* set 'M' bit */
|
|
tmp |= 0x40;
|
|
|
|
i = (SHORT)(ebufpos - emitbuf - ehoffset);
|
|
FIXBYTE(tmp + (i >> 8));
|
|
|
|
/* build low byte of location */
|
|
FIXBYTE(i);
|
|
|
|
/* output fixup data */
|
|
FIXBYTE(efixdat (pframe, ptarget, pso->doffset));
|
|
|
|
tmp = (pframe->symkind == EQU) ?
|
|
pframe->length: pframe->symu.ext.extIndex;
|
|
|
|
if (tmp >= 0x80)
|
|
FIXBYTE((tmp >> 8) + 0x80);
|
|
|
|
FIXBYTE(tmp);
|
|
|
|
tmp = (ptarget->symkind == EQU) ?
|
|
ptarget->length: ptarget->symu.ext.extIndex;
|
|
|
|
/* send target spec */
|
|
if (tmp >= 0x80)
|
|
FIXBYTE((tmp >> 8) + 0x80);
|
|
|
|
FIXBYTE(tmp);
|
|
|
|
if (pso->doffset) {
|
|
FIXBYTE(pso->doffset);
|
|
FIXBYTE((UCHAR)(pso->doffset >> 8));
|
|
#ifdef V386
|
|
if (FixupOp == 0x9D)
|
|
{
|
|
FIXBYTE((UCHAR)highWord(pso->doffset));
|
|
FIXBYTE((UCHAR)(highWord(pso->doffset) >> 8));
|
|
}
|
|
#endif
|
|
}
|
|
ecuroffset += dlen;
|
|
|
|
/* put zero bytes into data buffer */
|
|
while (dlen--)
|
|
OMFBYTE(0);
|
|
}
|
|
|
|
|
|
|
|
/*** mapFixup - map relocatable objects into the correct fixup type
|
|
*
|
|
*
|
|
* Entry *pdesc = parse stack entry
|
|
* Returns
|
|
* Sets fixtype and dsize
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
mapFixup (
|
|
register struct psop *pso
|
|
){
|
|
|
|
if (fNoMap)
|
|
return;
|
|
|
|
if ((1 << pso->fixtype & (M_FCONSTANT | M_FNONE)) &&
|
|
(pso->dsegment || pso->dflag == XTERNAL))
|
|
|
|
pso->fixtype = FOFFSET;
|
|
|
|
#ifdef V386
|
|
|
|
/* Remap OFFSET and POINTERS into there 32 bit types */
|
|
|
|
if (pso->mode > 4 || pso->dsize > 4 ||
|
|
(pso->dsegment && pso->dsegment->symkind == SEGMENT &&
|
|
pso->dsegment->symu.segmnt.use32 == 4) ||
|
|
pso->dcontext == pFlatGroup && pso->dsize == 4)
|
|
|
|
switch(pso->fixtype) {
|
|
|
|
case FOFFSET:
|
|
|
|
if (pso->dsize != 4)
|
|
errorc(E_IIS & ~E_WARN1);
|
|
|
|
else
|
|
pso->fixtype = F32OFFSET;
|
|
break;
|
|
|
|
case FPOINTER:
|
|
if (pso->dsize != 6)
|
|
errorc(E_IIS & ~E_WARN1);
|
|
|
|
else
|
|
pso->fixtype = F32POINTER;
|
|
break;
|
|
|
|
/* default is to do no mapping */
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/*** emitgetspec - set frame and target of parse entry
|
|
*
|
|
* emitgetspec (pframe, ptarget, pdesc);
|
|
*
|
|
* Entry pframe
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
emitgetspec (
|
|
SYMBOL FARSYM * *pframe,
|
|
SYMBOL FARSYM * *ptarget,
|
|
register struct psop *pso
|
|
){
|
|
|
|
if (pso->fixtype != FCONSTANT &&
|
|
pso->dflag == XTERNAL) {
|
|
|
|
*ptarget = pso->dextptr;
|
|
*pframe = pso->dsegment;
|
|
|
|
#ifndef FEATURE
|
|
/* externs without segments and the current assume is to
|
|
* flat space get a flat space segment frame */
|
|
|
|
if (! *pframe && pso->dextptr &&
|
|
regsegment[isCodeLabel(pso->dextptr) ? CSSEG: DSSEG] == pFlatGroup)
|
|
|
|
*pframe = pFlatGroup;
|
|
|
|
#endif
|
|
if (pso->dcontext)
|
|
*pframe = pso->dcontext;
|
|
}
|
|
else {
|
|
|
|
*ptarget = pso->dsegment; /* containing segment */
|
|
*pframe = pso->dcontext; /* context(?) of value */
|
|
}
|
|
|
|
if (!*pframe)
|
|
*pframe = *ptarget;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** efixdat - return fixdat byte
|
|
*
|
|
* routine (pframe, ptarget, roffset);
|
|
*
|
|
* Entry *pframe =
|
|
* *ptarget =
|
|
* roffset =
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
UCHAR PASCAL CODESIZE
|
|
efixdat (
|
|
SYMBOL FARSYM *pframe,
|
|
SYMBOL FARSYM *ptarget,
|
|
OFFSET roffset
|
|
){
|
|
register UCHAR tmp;
|
|
|
|
/* build fixdat byte */
|
|
tmp = 0;
|
|
/* 'F' bit is off */
|
|
/* 'T' bit is off */
|
|
if (roffset == 0) /* 'P' bit is on */
|
|
tmp = 4;
|
|
|
|
if (pframe)
|
|
if (M_XTERN & pframe->attr)
|
|
tmp += 2 << 4;
|
|
else if (pframe->symkind == GROUP)
|
|
tmp += 1 << 4;
|
|
|
|
/* frame part of fixdat */
|
|
|
|
if (ptarget)
|
|
if (M_XTERN & ptarget->attr)
|
|
tmp += 2;
|
|
else if (ptarget->symkind == GROUP)
|
|
tmp += 1;
|
|
|
|
return (tmp);
|
|
}
|
|
|
|
|
|
|
|
/*** edupitem - emit single dup item and count size
|
|
*
|
|
* edupitem (pdup);
|
|
*
|
|
* Entry *pdup = dup record
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
edupitem (
|
|
struct duprec FARSYM *pdup
|
|
){
|
|
register USHORT len;
|
|
UCHAR *cp;
|
|
|
|
if (nestCur > nestMax)
|
|
nestMax++;
|
|
|
|
if (ebufpos - emitbuf != EMITBUFSIZE + 1) {
|
|
len = wordsize+2;
|
|
|
|
if (pdup->dupkind == LONG)
|
|
len += pdup->duptype.duplong.llen + 1;
|
|
|
|
else if (pdup->dupkind == ITEM)
|
|
len += pdup->duptype.dupitem.ddata->dsckind.opnd.dsize + 1;
|
|
|
|
if (!EBUFOPEN(len))
|
|
ebufpos = emitbuf + EMITBUFSIZE + 1;
|
|
|
|
else {
|
|
emitsword ((USHORT)(pdup->rptcnt));
|
|
/* repeat count */
|
|
if (emitrecordtype & 1)
|
|
emitsword((USHORT)(pdup->rptcnt >> 16));
|
|
|
|
/* block count */
|
|
emitsword (pdup->itemcnt);
|
|
|
|
if (pdup->dupkind == LONG) {
|
|
cp = pdup->duptype.duplong.ldata;
|
|
len = pdup->duptype.duplong.llen;
|
|
|
|
OMFBYTE(len);
|
|
|
|
do {
|
|
OMFBYTE(*cp++);
|
|
} while (--len);
|
|
}
|
|
else if (pdup->dupkind == ITEM) {
|
|
OMFBYTE(pdup->duptype.dupitem.ddata->dsckind.opnd.dsize);
|
|
|
|
fIniter--;
|
|
emitobject (&pdup->duptype.dupitem.ddata->dsckind.opnd);
|
|
fIniter++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** emitdup - emit dup record and appropriate fixup record
|
|
*
|
|
* emitdup (pdup);
|
|
*
|
|
* Entry *pdup = dup record
|
|
* Exit
|
|
* Returns FALSE if dup is too large to fit in buffer
|
|
* Calls
|
|
*/
|
|
|
|
|
|
UCHAR PASCAL CODESIZE
|
|
emitdup (
|
|
struct duprec FARSYM *pdup
|
|
){
|
|
SHORT op;
|
|
|
|
op = (f386already) ? 0xA3 : 0xA2;
|
|
nestCur = nestMax = 0;
|
|
|
|
emitdumpdata ((UCHAR)op);
|
|
emitsetrecordtype ((UCHAR)op);
|
|
|
|
/* scan dup tree and emit dup items */
|
|
scandup (pdup, edupitem);
|
|
|
|
if (ebufpos - emitbuf == EMITBUFSIZE + 1) {
|
|
ebufpos = emitbuf;
|
|
ehoffset = 0;
|
|
efixpos = efixbuffer;
|
|
return(FALSE);
|
|
}
|
|
else {
|
|
flushbuffer ();
|
|
flushfixup ();
|
|
emitrecordtype = 0xFF;
|
|
}
|
|
return (nestMax <= 18);
|
|
}
|
|
|
|
|
|
/*** emitEndPass1 - emit end of pass1 info
|
|
*
|
|
*/
|
|
|
|
|
|
VOID PASCAL emitEndPass1()
|
|
{
|
|
|
|
emitsetrecordtype (0x88);
|
|
oEndPass1 = oOMFCur + 5; /* note offset of end of pass1 OMF record */
|
|
|
|
OMFBYTE(0);
|
|
emitsword(0x100 | 0xA2);
|
|
flushbuffer ();
|
|
}
|
|
|
|
|
|
|
|
/*** emitdone - produce end record
|
|
*
|
|
* emitdone (pdesc);
|
|
*
|
|
* Entry *pdesc = parse tree entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID PASCAL
|
|
emitdone (
|
|
DSCREC *pdesc
|
|
){
|
|
SYMBOL FARSYM *pframe;
|
|
SYMBOL FARSYM *ptarget;
|
|
OFFSET u;
|
|
UCHAR endOMFtype;
|
|
|
|
flushline();
|
|
|
|
if (!pdesc)
|
|
{
|
|
emitsetrecordtype (0x8A); /* RN */
|
|
/* emit null entry point marked in MOD TYP */
|
|
/* there is a point of contention here. some people
|
|
* (and decode.c, old assemblers and other things) say
|
|
* the low order bit is zero. others, such as the
|
|
* omf documentation, say the low order bit should be
|
|
* 1. since I dont know, and am trying to be compatable,
|
|
* I will obey the old tools. maybe I'll change this
|
|
* later... -Hans
|
|
* OMFBYTE(1); /* RN */
|
|
|
|
OMFBYTE(0);
|
|
}
|
|
else {
|
|
fKillPass1++;
|
|
u = pdesc->dsckind.opnd.doffset;
|
|
emitgetspec (&pframe, &ptarget, &pdesc->dsckind.opnd);
|
|
|
|
if (!ptarget || !pframe)
|
|
return;
|
|
|
|
endOMFtype = (cputype & P386)? 0x8B: 0x8A;
|
|
|
|
if (M_XTERN & ptarget->attr)
|
|
pframe = ptarget;
|
|
|
|
emitsetrecordtype (endOMFtype);
|
|
|
|
/* emit entry point information */
|
|
OMFBYTE(0xC1);
|
|
OMFBYTE(efixdat (pframe, ptarget, u) & ~4);
|
|
|
|
emitsindex (pframe->symu.segmnt.segIndex);
|
|
emitsindex (ptarget->symu.segmnt.segIndex);
|
|
|
|
emitsword((USHORT)u); /* output offset */
|
|
|
|
#ifdef V386
|
|
if (endOMFtype == 0x8B)
|
|
emitsword((USHORT)highWord(u));
|
|
#endif
|
|
}
|
|
flushbuffer ();
|
|
}
|
|
|
|
#ifndef M8086OPT
|
|
|
|
/*** EBYTE - Emit byte macro
|
|
*
|
|
* EBYTE ( ch )
|
|
*
|
|
* The bytes are buffered in obj.buf until the buffer fills
|
|
* then the buffer is written to disk via edump.
|
|
*
|
|
*/
|
|
|
|
#define EBYTE( ch ){\
|
|
if( !obj.cnt){\
|
|
edump();\
|
|
}\
|
|
obj.cnt--;\
|
|
checksum += *obj.pos++ = (char)ch;\
|
|
}
|
|
|
|
/*** ebuffer - write out object buffer
|
|
*
|
|
* Writes the record type, record length, record data, and checksum to
|
|
* the obj file. This is done via EBYTE which buffers the writes into
|
|
* obj.buf.
|
|
*
|
|
* Modifies obj.cnt, obj.pos, objerr, emitrecordtype
|
|
* Exit none
|
|
* Returns
|
|
* Calls farwrite
|
|
*/
|
|
|
|
VOID CODESIZE
|
|
ebuffer (
|
|
USHORT rectyp,
|
|
UCHAR *bufpos,
|
|
UCHAR *buffer
|
|
){
|
|
register UCHAR checksum;
|
|
register i;
|
|
USHORT nb;
|
|
|
|
|
|
if ((bufpos != buffer) && objing) {
|
|
nb = (USHORT)(bufpos - buffer + 1);
|
|
oOMFCur += nb + 3;
|
|
checksum = 0;
|
|
EBYTE(rectyp)
|
|
i = nb & 0xFF;
|
|
EBYTE( i )
|
|
i = nb >> 8;
|
|
EBYTE( i )
|
|
while (buffer < bufpos){
|
|
EBYTE( *buffer++ )
|
|
}
|
|
checksum = -checksum;
|
|
EBYTE( checksum );
|
|
}
|
|
emitrecordtype = 0;
|
|
}
|
|
|
|
|
|
/*** edump - dump the emit buffer
|
|
*
|
|
* edump ();
|
|
*
|
|
* The bytes buffered in obj.buf are dumped to disk. And
|
|
* the count and buffer position are reinitialized.
|
|
*
|
|
* Modifies obj.cnt, obj.pos, objerr
|
|
* Exit none
|
|
* Returns
|
|
* Calls farwrite
|
|
*/
|
|
|
|
VOID CODESIZE
|
|
edump()
|
|
{
|
|
|
|
# if defined MSDOS && !defined FLATMODEL
|
|
farwrite( obj.fh, obj.buf, (SHORT)(obj.siz - obj.cnt) );
|
|
# else
|
|
if (_write( obj.fh, obj.buf, obj.siz - obj.cnt )
|
|
!= obj.siz - obj.cnt)
|
|
objerr = -1;
|
|
# endif /* MSDOS */
|
|
|
|
obj.cnt = obj.siz;
|
|
obj.pos = obj.buf;
|
|
}
|
|
#endif /* M8086OPT */
|
|
|
|
|
|
#if !defined M8086OPT && !defined FLATMODEL
|
|
|
|
unsigned short _far _pascal DosWrite( unsigned short, unsigned char far *, unsigned short, unsigned short far *);
|
|
|
|
VOID farwrite( handle, buffer, count )
|
|
int handle;
|
|
UCHAR FAR * buffer;
|
|
SHORT count;
|
|
{
|
|
USHORT usWritten;
|
|
|
|
if( DosWrite( handle, buffer, count, &usWritten ) ){
|
|
objerr = -1;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
int emitFpo()
|
|
{
|
|
struct nameStruct {
|
|
SHORT hashval;
|
|
char id[20];
|
|
} nam = {0, ".debug$F"};
|
|
|
|
PFPOSTRUCT pFpo = pFpoHead;
|
|
SYMBOL sym;
|
|
UCHAR comb = 2; // public
|
|
UCHAR algn = 5; // relocatable
|
|
USHORT tmp = 0;
|
|
unsigned long offset = 0;
|
|
unsigned long data_offset = 0;
|
|
|
|
if (!pFpo) {
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* write out the externs for all fpo procs
|
|
* this must be done during pass1 so that the extdefs
|
|
* are written to the omf file before the pubdefs
|
|
*/
|
|
if (!pass2) {
|
|
flushbuffer();
|
|
for (pFpo=pFpoHead; pFpo; pFpo=pFpo->next) {
|
|
pFpo->extidx = externnum++;
|
|
emitsetrecordtype (0x8C);
|
|
emitSymbol(pFpo->pSym);
|
|
OMFBYTE(0);
|
|
flushbuffer();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* create the lnames record for the .debug$F section
|
|
*/
|
|
emitsetrecordtype (0x96);
|
|
memset(&sym,0,sizeof(SYMBOL));
|
|
sym.nampnt = (NAME*) &nam;
|
|
emitSymbol(&sym);
|
|
flushbuffer();
|
|
|
|
/*
|
|
* create the segdef record for the .debug$F section
|
|
*/
|
|
emitsetrecordtype (0x98);
|
|
OMFBYTE((algn<<5) + (comb<<2) + 1);
|
|
emitoffset(numFpoRecords*sizeof(FPO_DATA), 0);
|
|
emitsindex (lnameIndex);
|
|
emitsindex (1);
|
|
emitsindex (1);
|
|
flushbuffer();
|
|
|
|
/*
|
|
* now we have to cruise thru the list of fpo directives and
|
|
* fixup any cases where there are multiple fpo directives for
|
|
* a single procedure. the procedure size needs to be changed
|
|
* to account for the multiple directives.
|
|
*/
|
|
pFpo=pFpoHead;
|
|
flushbuffer();
|
|
do {
|
|
if ((pFpo->next) && (pFpo->next->pSym == pFpo->pSym)) {
|
|
// we must have a group (2 or more) fpo directives
|
|
// that are in the same function so lets fix them
|
|
do {
|
|
pFpo->fpoData.cbProcSize =
|
|
pFpo->next->fpoData.ulOffStart - pFpo->fpoData.ulOffStart;
|
|
pFpo = pFpo->next;
|
|
// now we must output a pubdef and a extdef for the
|
|
// fpo record. this is necessary because otherwise the
|
|
// linker will resolve the fixups to the first fpo record
|
|
// function.
|
|
pFpo->extidx = externnum++;
|
|
emitsetrecordtype (0x8C);
|
|
emitSymbol(pFpo->pSymAlt);
|
|
OMFBYTE(0);
|
|
flushbuffer();
|
|
emitglobal(pFpo->pSymAlt);
|
|
} while ((pFpo->next) && (pFpo->next->pSym == pFpo->pSym));
|
|
pFpo->fpoData.cbProcSize =
|
|
(pFpo->pSym->offset + pFpo->pSym->symu.plabel.proclen) -
|
|
pFpo->fpoData.ulOffStart;
|
|
}
|
|
else {
|
|
pFpo->fpoData.cbProcSize = pFpo->pSym->symu.plabel.proclen;
|
|
}
|
|
pFpo = pFpo->next;
|
|
} while (pFpo);
|
|
|
|
/*
|
|
* finally we scan the list of fpo directives and output the
|
|
* actual fpo records and associated fixups
|
|
*/
|
|
for (pFpo=pFpoHead; pFpo; pFpo=pFpo->next) {
|
|
/*
|
|
* emit the fpo record
|
|
*/
|
|
emitsetrecordtype (0xA4);
|
|
emitsindex (segmentnum);
|
|
emitoffset(data_offset,1);
|
|
data_offset += sizeof(FPO_DATA);
|
|
offset = pFpo->fpoData.ulOffStart;
|
|
pFpo->fpoData.ulOffStart = 0;
|
|
memcpy((void*)ebufpos, (void*)&pFpo->fpoData, sizeof(FPO_DATA));
|
|
ebufpos += sizeof(FPO_DATA);
|
|
/*
|
|
* emit the fixup record
|
|
*/
|
|
emitsetrecordtype (0x9D);
|
|
OMFBYTE(0xB8); // m=0, loc=14, offset=0
|
|
OMFBYTE(0x00); // offset=0
|
|
OMFBYTE(0x92); // f=1, frame=1, t=0, p=0, target=2
|
|
tmp = pFpo->extidx;
|
|
if (tmp >= 0x80) {
|
|
OMFBYTE((tmp >> 8) + 0x80);
|
|
}
|
|
OMFBYTE(tmp);
|
|
OMFBYTE(offset);
|
|
OMFBYTE(offset >> 8);
|
|
OMFBYTE(offset >> 16);
|
|
OMFBYTE(offset >> 24);
|
|
}
|
|
flushbuffer();
|
|
|
|
lnameIndex++;
|
|
segmentnum++;
|
|
|
|
return TRUE;
|
|
}
|