/* asmchksp.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 <ctype.h>
#include <float.h>
#include <stdlib.h>
#include <math.h>
#include <errno.h>
#include "asm86.h"
#include "asmfcn.h"
#include "asmctype.h"
#include "asmexpr.h"
#include "asmopcod.h"
extern UCHAR opprec [];
VOID CODESIZE setdispmode(struct ar *);
SHORT CODESIZE simpleExpr (struct ar *);
char fValidSym;
/*** createsym - make item entry for symbol
*
* createsym (itemkind, p);
*
* Entry itemkind = kind of item
* itemsub =
* *p = activation record
* Exit
* Returns
* Calls
* Note If symbol, look further to see if EQU, record name
* and do appropriate thing.
*/
VOID PASCAL CODESIZE createsym (
){
register struct psop *pso; /* parse stack operand structure */
register SYMBOL FARSYM *symp = symptr;
char aliasAttr = 0xFF;
struct dscrec *itemptrT;
pso = &(itemptr->dsckind.opnd);
if (!symp) {
undefined:
pso->dflag = UNDEFINED;
pso->dtype = M_CODE | M_FORTYPE;
return;
}
if (symp->symkind == EQU &&
symp->symu.equ.equtyp == ALIAS) {
aliasAttr = symptr->attr;
symptr = symp = chasealias (symp);
if (!symp)
goto undefined;
}
else if (symp->symkind == REC && (PEEKC () == '<')) {
itemptrT = itemptr;
pso->doffset = recordparse ();
itemptr = itemptrT;
return;
}
/* Assume symbol is defined */
if (M_XTERN & symp->attr)
pso->dflag = XTERNAL;
else if (!(M_DEFINED & symp->attr)) {
/* Cause error if undefined */
pso->dflag = UNDEFINED;
errorn (E_SND);
}
else if (!(M_BACKREF & (symp->attr & aliasAttr)))
pso->dflag = FORREF;
else
pso->dflag = KNOWN;
if (M_MULTDEFINED & symp->attr)
errorc (E_RMD);
pso->dsize = symp->symtype;
pso->dlength = symp->length;
pso->doffset = symp->offset;
pso->dcontext = (SYMBOL FARSYM *)NULL;
if ((symp->symkind == EQU) && (symp->symu.equ.equtyp == EXPR)) {
pso->dsign = symp->symu.equ.equrec.expr.esign;
pso->dcontext = symp->symu.equ.equrec.expr.eassume;
}
if (1 << symp->symkind & (M_CLABEL | M_PROC))
if (isCodeLabel(symp) && emittext)
pso->dcontext = symp->symu.clabel.csassume;
if (1 << symp->symkind & (M_REGISTER | M_GROUP | M_SEGMENT))
pso->dsegment = symp;
else
pso->dsegment = symp->symsegptr;
if ((M_XTERN & symp->attr) || (1 << symp->symkind & (M_REC | M_RECFIELD)))
pso->dextptr = symp;
pso->dtype = xltsymtoresult[symp->symkind];
if (symp->symkind == CLABEL ||
symp->symkind == EQU && pso->dsegment)
if (isCodeLabel(symp))
pso->dtype = M_CODE;
else
pso->dtype = M_DATA;
if (!(M_BACKREF & (symp->attr & aliasAttr)))
pso->dtype |= M_FORTYPE;
if ((pso->dtype == xltsymtoresult[REGISTER]) &&
(symp->symu.regsym.regtype == STKREG)) {
/* 8087 support */
flteval ();
}
}
/*** evalalpha - evaluate alpha
*
* type = evalpha (p);
*
* Entry p = pointer to parser activation record
* Exit alpha item added to parse stack
* Returns type of item added to parse stack
* Calls
*/
UCHAR PASCAL CODESIZE
evalalpha (
register struct ar *p
){
register struct psop *pso; /* parse stack operand entry */
if (! fValidSym)
getatom ();
if (fValidSym == 2 || symsearch ()){
fValidSym = 0;
if (symptr->symkind == EQU && symptr->symu.equ.equtyp == TEXTMACRO) {
#ifdef BCBOPT
goodlbufp = FALSE;
#endif
expandTM (symptr->symu.equ.equrec.txtmacro.equtext);
return (getitem (p));
}
else if (symptr->symkind == CLASS)
errorn( E_IOT );
else {
addplusflagCur = FALSE;
createitem (OPERAND, ISYM);
p->addplusflag = addplusflagCur;
return (OPERAND);
}
}
fValidSym = 0;
if (fnoper ())
if ((opertype == OPNOTHING) || (opertype == OPDUP)) {
lbufp = begatom;
dupflag = (opertype == OPDUP);
return (ENDEXPR);
}
else {
createitem (OPERATOR, ISYM);
return (OPERATOR);
}
else if (*naim.pszName == '.') {
lbufp = begatom + 1;
operprec = opprec[opertype = OPDOT];
createitem (OPERATOR, ISYM);
return (OPERATOR);
}
else if (fnsize ()) {
createitem (OPERAND, ISIZE);
return (OPERAND);
}
else if ((*naim.pszName == '$') && (naim.pszName[1] == 0)) {
itemptr = defaultdsc ();
pso = &(itemptr->dsckind.opnd);
/* Create result entry */
pso->doffset = pcoffset;
pso->dsegment = pcsegment;
pso->dcontext = pcsegment;
pso->dtype = M_CODE;
pso->dsize = CSNEAR;
return (OPERAND);
}
else if ((*naim.pszName == '?') && (naim.pszName[1] == 0)) {
createitem (OPERAND, IUNKNOWN);
if (emittext)
errorc (E_UID);
return (OPERAND);
}
else {
symptr = (SYMBOL FARSYM *)NULL;
error (E_SND, naim.pszName); /* common pass1 error */
createitem (OPERAND, ISYM);
return (OPERAND);
}
}
/* Dup tree is organized left to right horizonatally for each
item in a DUP list at the same level( i. e. 5 DUP(1,2,3) ).
This is considered the 'list' part. Any item in the list
may be another DUP header instead of a data entry, in
which case you go down a level and have another list.
*/
/*** scanlist - scan duprec list
*
* scanlist (ptr, disp);
*
* Entry *ptr = duprec entry
* disp = function to execute on entry
* Exit depends upon function
* Returns none
* Calls
*/
VOID PASCAL CODESIZE
scanlist (
struct duprec FARSYM *ptr,
VOID (PASCAL CODESIZE *disp) (struct duprec FARSYM *)
){
struct duprec FARSYM *iptr;
struct duprec FARSYM *dptr;
nestCur++;
while (ptr) {
/* set pointer to next entry */
iptr = ptr->itemlst;
if (ptr->dupkind == NEST)
/* dptr = pointer to duplicated item */
dptr = ptr->duptype.dupnext.dup;
else
dptr = (struct duprec FARSYM *)NULL;
if (!(ptr->rptcnt == 1 && ptr->itemcnt) ||
!(strucflag && initflag))
(*disp) (ptr);
if (dptr) {
/* Go thru DUP list */
scanlist (dptr, disp);
if (displayflag)
if (!(ptr->rptcnt == 1 && ptr->itemcnt) ||
!(strucflag && initflag))
enddupdisplay ();
}
if (ptr == iptr) /* corrupt data structure */
break;
/* Handle next in list */
ptr = iptr;
}
nestCur--;
}
/*** calcsize - calculate size of DUP list
*
* value = calcsize (ptr);
*
* Entry *ptr = dup list
* Exit none
* Returns size of structure
* Calls calcsize
*/
OFFSET PASCAL CODESIZE
calcsize (
struct duprec FARSYM *ptr
){
unsigned long clsize = 0, nextSize, limit;
struct duprec FARSYM *p;
limit = (wordsize == 2)? 0x10000: 0xffffffff;
for (p = ptr; p; p = p->itemlst) {
if (p->dupkind == NEST) {
/* Process nested dup */
nextSize = calcsize (p->duptype.dupnext.dup);
if (nextSize && (p->rptcnt > limit / nextSize))
errorc(E_VOR);
nextSize *= p->rptcnt;
}
else {
if (p->dupkind == LONG) {
nextSize = p->duptype.duplong.llen;
resvspace = FALSE;
}
else {
/* Size is that of directive */
nextSize = p->duptype.dupitem.ddata->dsckind.opnd.dsize;
if (p->duptype.dupitem.ddata->dsckind.opnd.dflag != INDETER)
resvspace = FALSE;
}
}
if (nextSize > limit - clsize)
errorc(E_VOR);
clsize += nextSize;
if (p == p->itemlst) /* corrupt data structure */
break;
}
return (clsize);
}
/*** datascan - scan next data item
*
* datascan ();
*
* Entry
* Exit
* Returns
* Calls
*/
struct duprec FARSYM * PASCAL CODESIZE
datascan (
struct datarec *p
){
register char cc;
struct dsr a;
if (ISBLANK (PEEKC ()))
skipblanks ();
a.initlist = a.flag = a.longstr = FALSE;
/* check for textmacro substitution */
a.dirscan = lbufp;
xcreflag--;
getatom ();
if (fnsize())
goto isASize;
if (symsrch ())
if (symptr->symkind == EQU &&
symptr->symu.equ.equtyp == TEXTMACRO) {
expandTM (symptr->symu.equ.equrec.txtmacro.equtext);
a.dirscan = begatom;
}
else if (symptr->symkind == STRUC) {
isASize:
switchname();
getatom();
if (tokenIS("ptr")) {
switchname();
p->type = fnPtr(datadsize[optyp - TDB]);
if (p->type > 512)
goto noRescan;
}
}
lbufp = a.dirscan;
noRescan:
xcreflag++;
if ((optyp == TDB &&
((cc = PEEKC ()) == '\'' || cc == '"')) &&
!initflag)
datadb (&a);
if (optyp != TDB && optyp != TDW)
/* entry can be DD | DQ | DT */
parselong (&a);
if (!a.longstr)
datacon (&a);
else if (strucflag && initflag)
errorc( E_OIL );
if (!a.flag) {
if (!strucflag || !initflag) {
a.dupdsc->rptcnt = 1;
a.dupdsc->itemcnt = 0;
a.dupdsc->itemlst = (struct duprec FARSYM *)NULL;
}
}
return (a.dupdsc);
}
/*** realeval - evaluate IEEE 8087 floating point number
*
* realeval (p);
*
* Entry
* Exit
* Returns
* Calls
*/
struct ddecrec {
USHORT realv[5];
USHORT intgv[2];
USHORT cflag;
};
#if !defined FLATMODEL
// Because this is called so seldom and it's so slow anyhow put it in
// a far segment.
# pragma alloc_text (FA_TEXT, realeval)
#endif
VOID PASCAL
realeval (
struct realrec *p
){
register char cc, *cp;
char numtext[61];
struct ddecrec fltres;
#if !defined NOFLOAT
float *pTmpFloat;
double *pTmpDouble;
double TmpDouble;
double AbsDouble;
long double *pTmpLongDouble;
char *pEnd;
#endif
cp = numtext;
/* Copy the number - must have at least 1 char */
*cp++ = NEXTC (); /* get leading sign or 1st char */
do {
cc = NEXTC ();
*cp++ = cc;
} while (isdigit (cc) || cc == '.');
if ((cc = MAP (cc)) == 'E') {
/* Get the next + - or digit */
*cp++ = NEXTC ();
/* Copy the exponent over */
do {
cc = NEXTC ();
*cp++ = cc;
} while (isdigit (cc));
}
*cp = '\0';
BACKC ();
// NOFLOAT is used when there are no floating point libraries available
// Any masm version produced with NOFLOAT defined will cause a divide
// by 0 error to be logged when a real number initializer is used.
#if defined NOFLOAT
ferrorc( E_DVZ );
#else
switch(optyp)
{
case TDD:
errno = 0;
TmpDouble = strtod( numtext, &pEnd );
if( errno == ERANGE ){
ferrorc( E_DVZ );
}
AbsDouble = TmpDouble > 0 ? TmpDouble : -TmpDouble;
if( AbsDouble > FLT_MAX || AbsDouble < FLT_MIN ){
ferrorc( E_DVZ );
}else{
// Convert the double to a float (8 byte to 4 byte)
pTmpFloat = (float *)(p->num);
*pTmpFloat = (float)TmpDouble;
}
break;
case TDQ:
pTmpDouble = (double *)(p->num);
errno = 0;
*pTmpDouble = strtod( numtext, &pEnd );
if( errno == ERANGE ){
ferrorc( E_DVZ );
}
break;
case TDT:
pTmpLongDouble = (long double *)(p->num);
errno = 0;
*pTmpLongDouble = _strtold( numtext, &pEnd );
if( errno == ERANGE ){
ferrorc( E_DVZ );
}
break;
default:
ferrorc(E_TIL);
break;
}
#endif
}
/*** simpleExpr - short curcuit expression evaluator
*
*/
/* following are three protype parse records for the three simple
* expressions that we simpleExpr understands
*/
#ifdef EXPR_STATS
long cExpr, cHardExpr;
extern char verbose;
#endif
#define SHORT_CIR 1
#if SHORT_CIR
DSCREC consDS = {
NULL, 0, 0, /* previtem, prec, type */
{ NULL, NULL, NULL, 0, /* dsegment, dcontext, dexptr, dlength */
6, /* rm */
1 << RCONST, /* dtype */
0, 0, /* 0, */ /* doffset, dsize, type */
4, /* mode */
FALSE, FALSE, FALSE, /* w, s, sized*/
NOSEG, /* seg */
KNOWN, /* dflag */
FCONSTANT, /* fixtype */
FALSE /* dsign */
}
};
DSCREC regDS = {
NULL, 0, 0, /* previtem, prec, type */
{ NULL, NULL, NULL, 0, /* dsegment, dcontext, dexptr, dlength */
0, /* rm */
1 << REGRESULT, /* dtype */
0, 2, /* 0, */ /* doffset, dsize, type */
3, /* mode */
TRUE, FALSE, TRUE, /* w, s, sized*/
NOSEG, /* seg */
KNOWN, /* dflag */
FCONSTANT, /* fixtype */
FALSE /* dsign */
}
};
DSCREC labelDS = {
NULL, 0, 0, /* previtem, prec, type */
{ NULL, NULL, NULL, 0, /* dsegment, dcontext, dexptr, dlength */
6, /* rm */
1 << DATA, /* dtype */
0, 2, /* 0, */ /* doffset, dsize, type */
0, /* mode */
TRUE, FALSE, TRUE, /* w, s, sized*/
NOSEG, /* seg */
KNOWN, /* dflag */
FNONE, /* fixtype */
FALSE /* dsign */
}
};
#if !defined XENIX286 && !defined FLATMODEL
#pragma check_stack-
#endif
SHORT CODESIZE
simpleExpr (
struct ar *pAR
){
register DSCREC *pDES; /* parse stack operand structure */
register char kind;
char cc;
char *lbufSav;
fValidSym = noexp = 0;
lbufSav = lbufp;
#ifdef EXPR_STATS
cExpr++;
#endif
if (ISTERM (cc = skipblanks())) {
notSimple:
lbufp = lbufSav;
notSimpleLab:
#ifdef EXPR_STATS
cHardExpr++;
#endif
return (FALSE);
}
if (LEGAL1ST (cc)){
getatom ();
fValidSym++; /* 1 means valid token */
if (! (ISTERM (PEEKC()) || PEEKC() == ',')){
#ifdef EXPR_STATS
if (verbose && pass2)
fprintf(stdout, "Not a Simple Expression: %s\n", lbufSav);
#endif
goto notSimpleLab;
}
if (symsearch ()){
fValidSym++; /* 2 means valid symptr */
if ((kind = symptr->symkind) == REGISTER &&
(symptr->symu.regsym.regtype != STKREG)) {
pAR->curresult = pDES = dalloc();
*pDES = regDS;
pDES->dsckind.opnd.dsegment = symptr;
switch (symptr->symu.regsym.regtype) {
case BYTREG:
pDES->dsckind.opnd.dsize = 1;
pDES->dsckind.opnd.w--;
pDES->dsckind.opnd.s++;
break;
#ifdef V386
case CREG:
if (opctype != PMOV)
errorc(E_WRT);
case DWRDREG:
pDES->dsckind.opnd.dsize = 4;
break;
#endif
}
pDES->dsckind.opnd.rm = symptr->offset;
return(TRUE);
}
else if (kind == CLABEL || kind == PROC || kind == DVAR ||
(kind == EQU && symptr->symu.equ.equtyp == EXPR)) {
pAR->curresult = pDES = dalloc();
*pDES = labelDS;
pDES->dsckind.opnd.doffset = symptr->offset;
pDES->dsckind.opnd.dsegment = symptr->symsegptr;
if (kind == EQU) {
if (! (pDES->dsckind.opnd.dcontext =
symptr->symu.equ.equrec.expr.eassume) &&
! pDES->dsckind.opnd.dsegment){
val = pDES->dsckind.opnd.doffset;
*pDES = consDS;
pDES->dsckind.opnd.dsign =
symptr->symu.equ.equrec.expr.esign;
if (!(M_BACKREF & symptr->attr)){
pDES->dsckind.opnd.dtype |= M_FORTYPE;
pDES->dsckind.opnd.dflag = FORREF;
}
if (M_XTERN & symptr->attr){
pDES->dsckind.opnd.dflag = XTERNAL;
pDES->dsckind.opnd.dextptr = symptr;
return (TRUE);
}
goto constEqu;
}
}
pDES->dsckind.opnd.dsize = symptr->symtype;
pDES->dsckind.opnd.dlength = symptr->length;
if (M_XTERN & symptr->attr){
pDES->dsckind.opnd.dflag = XTERNAL;
pDES->dsckind.opnd.dextptr = symptr;
}
else if (!(M_DEFINED & symptr->attr)) {
/* Cause error if undefined */
pDES->dsckind.opnd.dflag = UNDEFINED;
pDES->dsckind.opnd.dsize = wordsize;
pDES->dsckind.opnd.dtype = M_CODE;
errorn (E_SND);
}
else if (!(M_BACKREF & symptr->attr)){
pDES->dsckind.opnd.dflag = FORREF;
pDES->dsckind.opnd.dtype |= M_FORTYPE;
}
if (M_MULTDEFINED & symptr->attr)
errorc (E_RMD);
if (pDES->dsckind.opnd.dsize < 2) {
pDES->dsckind.opnd.w--;
pDES->dsckind.opnd.s++;
}
#ifdef V386
if (wordsize == 4 ||
(symptr->symsegptr && symptr->symsegptr->symu.segmnt.use32 == 4)) {
pDES->dsckind.opnd.mode = 5;
pDES->dsckind.opnd.rm--; /* = 5 */
}
#endif
if (isCodeLabel(symptr)){
pDES->dsckind.opnd.dtype =
pDES->dsckind.opnd.dtype & ~M_DATA | M_CODE;
if (emittext && kind != EQU)
pDES->dsckind.opnd.dcontext =
symptr->symu.clabel.csassume;
}
else {
pAR->linktype = FNONE;
pAR->rstype = M_DATA;
findsegment ((UCHAR)pAR->index, pAR);
pDES->dsckind.opnd.seg = pAR->segovr;
}
pDES->dsckind.opnd.fixtype = FOFFSET;
return(TRUE);
}
#ifdef EXPR_STATS
if (verbose && pass2)
fprintf(stdout, "Not a Simple Label: %s\n", naim.pszName);
#endif
}
goto notSimpleLab;
}
if (isdigit (cc)){
evalconst (); /* value in global val */
if (! (ISTERM (skipblanks()) || PEEKC() == ','))
goto notSimple;
pAR->curresult = pDES = dalloc();
*pDES = consDS;
constEqu:
if (pDES->dsckind.opnd.dflag != FORREF) {
if (val < 128)
pDES->dsckind.opnd.s++;
else {
#ifdef V386 /* only consider 16 bits */
if (wordsize == 2)
pDES->dsckind.opnd.s = (USHORT)(((USHORT) val & ~0x7F ) == (USHORT)(~0x7F));
else
#endif
pDES->dsckind.opnd.s = ((val & ~0x7F ) == ~0x7F);
}
}
pDES->dsckind.opnd.doffset = val;
if (val > 256){
pDES->dsckind.opnd.w++;
pDES->dsckind.opnd.sized++;
}
return(TRUE);
}
goto notSimple;
}
#if !defined XENIX286 && !defined FLATMODEL
#pragma check_stack+
#endif
#endif
/*** expreval - expression evaluator
*
* routine ();
*
* Entry
* Exit
* Returns
* Calls
*/
DSCREC * PASCAL CODESIZE
expreval (
UCHAR *dseg
){
register struct psop *psoi; /* parse stack operand structure */
struct ar a;
SHORT i;
dupflag = FALSE;
nilseg = NOSEG;
a.segovr = NOSEG;
a.index = *dseg;
#if SHORT_CIR
if (simpleExpr(&a)){
fSecondArg++;
return (a.curresult);
}
#endif
a.exprdone = a.addplusflag = FALSE;
a.lastitem = (DSCREC *)NULL;
/* No parens or [] yet, Lowest precedence, haven't found anything yet */
a.parenlevel = a.bracklevel = a.lastprec = a.index = a.base = 0;
noexp = 1;
/* Start expression loop */
while (!a.exprdone){
switch (getitem (&a)) {
case OPERAND:
itemptr->previtem = a.lastitem;
a.lastitem = itemptr;
itemptr->prec = a.lastprec;
noexp = 0;
break;
case OPERATOR:
exprop (&a);
noexp = 0;
break;
case ENDEXPR:
a.exprdone = TRUE;
}
}
/* Do some easy error checking */
if (a.parenlevel + a.bracklevel)
errorc (E_PAR);
itemptr = (DSCREC *)NULL;
if (!a.lastitem)
a.curresult = defaultdsc ();
else
evaluate (&a); /* Evaluate whole expression */
psoi = &(a.curresult->dsckind.opnd);
a.rstype = psoi->dtype &
(M_CODE|M_DATA|M_RCONST|M_REGRESULT|M_SEGRESULT|M_GROUPSEG);
a.linktype = FNONE; /* Leave bits for link type */
a.vmode = 4;
psoi->sized = FALSE;
psoi->w = TRUE;
psoi->s = FALSE;
#ifdef V386
if ((a.base|a.index) & 0xf8) { /* have 386 index or base */
if (a.index) {
if (!(a.index&8))
errorc(E_OCI);
if ((a.index&7) == 4)
errorc(E_DBR);
a.vmode = 10; /* two register modes */
/* here we are putting what goes into the SIB
* into a.index. from here on, we have to
* to a.index with masks, so we dont trash
* the high order stuff
* the encoding we derive this from is tricky--
* see regcheck() for details -Hans
* stick in the index register */
i = (a.index&7) << 3;
/* stick in base. ebp if there is none */
if (a.base){
if (!(a.base&8))
errorc(E_OCI);
i |= (a.base&7);
}
else {
i |= 5;
a.vmode = 8;
}
/* stick in scale. *1 if there is none */
if (a.index&0x70)
i |= ((a.index & 0x70) - 0x10) << 2;
a.index = i;
}
else if (a.base == (4|8)) { /* esp */
a.vmode = 10;
a.index = 044;
}
else { /* one register modes */
a.vmode = 7;
a.index = a.base & 7;
}
/* note dirty way of checking for BP or SP */
if (*dseg != ESSEG && (a.base&6) == 4)
*dseg = SSSEG;
} else
#endif /* V386 */
if (a.base + a.index){ /* Have some index or base */
a.vmode = 2;
/* Assume offset is direct */
if (a.base && a.index) /* Have both */
a.index = a.base - 3 + a.index - 6;
else if (a.base) /* Have base address */
a.index = (a.base == 3)? 7: 6;
else /* Have only index address*/
a.index = a.index - 2;
if (1 << a.index & (1 << 2 | 1 << 3 | 1 << 6) && *dseg != ESSEG)
*dseg = SSSEG;
}
/* No indexing */
else if (a.rstype == xltsymtoresult[REGISTER]) {
/* Have register */
a.vmode = 3;
psoi->sized = TRUE;
switch(psoi->dsegment->symu.regsym.regtype) {
case BYTREG:
psoi->dsize = 1;
goto mask7;
case WRDREG:
case INDREG:
case SEGREG:
case STKREG:
psoi->dsize = 2;
goto mask7;
#ifdef V386
case CREG:/* probably should turn this into memref if !386P */
if (opctype != PMOV)
errorc(E_WRT);
psoi->dsize = 4;
a.index = psoi->doffset;
break;
case DWRDREG:
psoi->dsize = 4;
#endif
mask7:
if ((psoi->doffset > 7) || psoi->dsign)
errorc (E_IRV);
/* Set register # */
a.index = psoi->doffset & 7;
break;
default:
errorc(E_WRT);
break;
}
}
/* Might be segment result */
else if (a.rstype & (M_SEGRESULT | M_GROUPSEG)) {
/* we get here if we had offset operator with segment or group
* or offset operator with data and rconst
* Result is SEG. Rconst if OFFSET grp:var */
if (a.rstype & (M_SEGRESULT | M_EXPLOFFSET)) {
psoi->dsize = 2;
/* Leave size if not OFFSET or */
psoi->sized = TRUE;
}
a.linktype = FOFFSET;
if ((M_GROUPSEG & a.rstype) && (psoi->fixtype != FOFFSET)) {
a.linktype = FGROUPSEG;
setdispmode(&a);
}
if ((a.vmode == 4) && (psoi->fixtype != FOFFSET))
a.linktype = FBASESEG;
}
else
a.index = 6;
/**** Evaluate offset part of result ****/
a.base = psoi->doffset;
if (psoi->fixtype == FOFFSET ||
a.vmode == 2 || a.vmode == 7 || a.vmode == 10)
psoi->dtype |= M_RCONST;
/* [] implicit const */
if ((M_RCONST & psoi->dtype) &&
(a.linktype == FNONE) && (a.vmode != 3)) {
/* Need to make sure <s> not set if memory */
if (!(psoi->dflag & (FORREF|UNDEFINED|XTERNAL))
&& !psoi->dsegment && psoi->fixtype == FCONSTANT) {
psoi->s = (a.base < 128 && !psoi->dsign) ||
(a.base < 129 && psoi->dsign);
if (!(psoi->s || psoi->dsign))
#ifdef V386 /* only consider 16 bits */
if (wordsize == 2 && a.vmode < 6)
psoi->s = (USHORT)(((USHORT) a.base & ~0x7F ) == (USHORT)(~0x7F));
else
#endif
psoi->s = ((a.base & ~0x7F ) == ~0x7F);
}
psoi->w = (psoi->dsign && a.base > 256) ||
(a.base > 255 && !psoi->dsign);
if (a.vmode != 4) {
/* This is offset for index */
/* If value not known, don't allow shortning to mode 1 */
/* Word or byte offset */
if (!(M_FORTYPE & psoi->dtype) &&
psoi->dsegment == 0 && psoi->s &&
a.vmode != 8) {
/* one byte offset */
a.vmode--;
if (a.base == 0 && psoi->dflag == KNOWN) {
/* perhaps 0 byte offset */
switch(a.vmode) {
case 1:
if (a.index != 6)
a.vmode--;
break;
case 6:
case 9:
if ((a.index&7) != 5)
a.vmode--;
break;
}
}
}
}
else { /* Must be immediate */
if (!psoi->dsegment && !psoi->dcontext)
a.linktype = FCONSTANT;
/******????? I'm not exactly sure why
* we think we have a size yet. seems
* to me mov BYTE PTR mem,500 is legal
* albeit silly. -Hans */
psoi->sized = psoi->w;
if (!(M_EXPLOFFSET & psoi->dtype) && psoi->dcontext) {
/* Have segreg:const */
a.vmode = 0;
if (!(M_PTRSIZE & psoi->dtype) && psoi->dsize == 0)
psoi->dsize = wordsize;
}
}
}
else if ((a.rstype & (M_DATA | M_CODE)) && a.linktype == FNONE) {
/* Have direct mode and Want offset */
a.linktype = FOFFSET;
setdispmode(&a);
if (psoi->dsize == CSFAR && emittext)
a.linktype = FPOINTER;
}
if (psoi->dflag == UNDEFINED) {
/* Forward ref pass 1 */
if (psoi->dsize == 0)
psoi->dsize = wordsize;
if (!(M_RCONST & psoi->dtype) && a.vmode == 4)
setdispmode(&a);
}
if (!psoi->dsegment ||
(1 << a.linktype & (M_FNONE|M_FOFFSET|M_FPOINTER|M_FGROUPSEG))){
if (psoi->dcontext &&
psoi->dcontext->symkind == REGISTER)
/* Have reg:var */
if (psoi->dcontext->symu.regsym.regtype == SEGREG) {
/* Have segreg:VAR */
a.segovr = psoi->dcontext->offset;
psoi->dcontext = regsegment[a.segovr];
/* Context is that of segreg */
if (!psoi->dsegment && (psoi->dflag != XTERNAL)) {
psoi->dcontext = NULL;
psoi->dtype = xltsymtoresult[REC];
psoi->mode = 4;
a.linktype = FCONSTANT;
}
}
else
errorc (E_IUR);
else /* Find if seg:var or no :, but needed */
findsegment (*dseg, &a);
}
/* bogus error check removed, dcontext can be other then register
*
* else if (psoi->dcontext &&
* psoi->dcontext->symu.regsym.regtype == SEGREG)
*
* errorc (E_IOT);
*/
if (a.segovr != NOSEG)
psoi->dtype |= xltsymtoresult[DVAR];
if (a.vmode == 2 || a.vmode == 7 || a.vmode == 10) {
if (a.segovr == NOSEG && *dseg != NOSEG &&
(psoi->dsegment || psoi->dflag == XTERNAL))
psoi->dcontext = regsegment[*dseg];
psoi->dtype |= xltsymtoresult[DVAR];
}
if (! (1 << a.linktype & (M_FNONE | M_FCONSTANT)) ||
psoi->dflag == XTERNAL) {
if (M_HIGH & psoi->dtype)
a.linktype = FHIGH;
if (M_LOW & psoi->dtype)
a.linktype = FLOW;
}
if ((psoi->dtype & (M_PTRSIZE | M_HIGH | M_LOW)) ||
psoi->dsize && a.vmode != 4) {
psoi->sized = TRUE;
psoi->w = (psoi->dsize > 1);
psoi->s = !psoi->w;
}
psoi->seg = a.segovr;
psoi->mode = a.vmode;
psoi->fixtype = a.linktype;
psoi->rm = a.index;
if ((M_REGRESULT & a.rstype) && (a.vmode != 3))
errorc (E_IUR); /* bad use of regs, like CS:SI */
fSecondArg++;
return (a.curresult);
}
/* setdispmode -- set up elements of the ar structure to reflect
the encoding of the disp addressing mode: [BP] or [EBP] means.
there is a wordsize length displacement following and a zero
index.
input : struct ar *a; a pointer to the upper frame variable
output : none
modifies : a->vmode, a->index.
*/
VOID CODESIZE
setdispmode(
register struct ar *a
){
#ifdef V386
if (a->vmode > 7) {
a->vmode = 8; /* scaled index byte, not r/m */
a->index = (a->index&~7) | 5;
}
else if (wordsize == 4 ||
highWord(a->curresult->dsckind.opnd.doffset) ||
(a->curresult->dsckind.opnd.dsegment &&
a->curresult->dsckind.opnd.dsegment->symu.segmnt.use32 == 4)) {
a->vmode = 5;
a->index = (a->index&~7) | 5;
}
else
#endif
{
a->vmode = 0;
a->index = 6;
}
}