/* 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 #include #include "asm86.h" #include "asmfcn.h" #define LINBUFSIZE EMITBUFSIZE - 20 /* line # records can't as big */ #define OMFBYTE(c) *ebufpos++ = (c) #define FIXBYTE(c) *efixpos++ = (c) #define LINBYTE(c) *elinpos++ = (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 = 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 brain damage 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 = 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 = 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++ = 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 = 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; }