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