Plan 9 from Bell Labs’s /usr/web/sources/contrib/rsc/86a/assem.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include "all.h"

/* implicit operands, not needed for assembly */
#define AFv ANONE
#define AXb ANONE
#define AXv ANONE
#define AYb ANONE
#define AYv ANONE
#define A0 ANONE
#define A1 ANONE
#define A2 ANONE
#define A3 ANONE
#define A4 ANONE
#define AMa2 ANONE

typedef struct Optab Optab;
struct Optab {
	int op;
	uchar arg1;
	uchar arg2;
	uchar arg3;
};

static uchar needmodrm[NAMODE] = {
[AEb] 1,
[AEv] 1,
[AGb] 1,
[AGv] 1,
[AM]  1,
[AMp] 1,
[ASw] 1,
};

/*
static uchar small[NAMODE] = {
[ANONE]	1,
[AEb] 1,
[AGb] 1,
[AOb] 1,
[AXb] 1,
[AYb] 1,
[AIb] 1,
[AAL] 1,
[ABL] 1,
[ACL] 1,
[ADL] 1,
[AAH] 1,
[ABH] 1,
[ACH] 1,
[ADH] 1,
};
*/

static Optab optab[256] = {
//00
  {OADD,  AEb, AGb}, {OADD,  AEv, AGv}, {OADD,  AGb, AEb}, {OADD,  AGv, AEv},
  {OADD,  AAL, AIb}, {OADD,  AAX, AIv}, {OPUSH, AES,    }, {OPOP,  AES     },
  {OOR,   AEb, AGb}, {OOR,   AEv, AGv}, {OOR,   AGb, AEb}, {OOR,   AGv, AEv},
  {OOR,   AAL, AIb}, {OOR,   AAX, AIv}, {OPUSH, ACS,    }, {OBAD,           },
//10
  {OADC,  AEb, AGb}, {OADC,  AEv, AGv}, {OADC,  AGb, AEb}, {OADC,  AGv, AEv},
  {OADC,  AAL, AIb}, {OADC,  AAX, AIv}, {OPUSH, ASS,    }, {OPOP,  ASS,    },
  {OSBB,  AEb, AGb}, {OSBB,  AEv, AGv}, {OSBB,  AGb, AEb}, {OSBB,  AGv, AEv},
  {OSBB,  AAL, AIb}, {OSBB,  AAX, AIv}, {OPUSH, ADS,    }, {OPOP,  ADS,    },
//20
  {OAND,  AEb, AGb}, {OAND,  AEv, AGv}, {OAND,  AGb, AEb}, {OAND,  AGv, AEv},
  {OAND,  AAL, AIb}, {OAND,  AAX, AIv}, {OSEG,  AES,    }, {ODAA,          },
  {OSUB,  AEb, AGb}, {OSUB,  AEv, AGv}, {OSUB,  AGb, AEb}, {OSUB,  AGv, AEv},
  {OSUB,  AAL, AIb}, {OSUB,  AAX, AIv}, {OSEG,  ACS,    }, {ODAS,          },
//30
  {OXOR,  AEb, AGb}, {OXOR,  AEv, AGv}, {OXOR,  AGb, AEb}, {OXOR,  AGv, AEv},
  {OXOR,  AAL, AIb}, {OXOR,  AAX, AIv}, {OSEG,  ASS,    }, {OAAA,          },
  {OCMP,  AEb, AGb}, {OCMP,  AEv, AGv}, {OCMP,  AGb, AEb}, {OCMP,  AGv, AEv},
  {OCMP,  AAL, AIb}, {OCMP,  AAX, AIv}, {OSEG,  ADS,    }, {OAAS,          },
//40
  {OINC,  AAX,    }, {OINC,  ACX,    }, {OINC,  ADX,    }, {OINC,  ABX,    },
  {OINC,  ASP,    }, {OINC,  ABP,    }, {OINC,  ASI,    }, {OINC,  ADI,    },
  {ODEC,  AAX,    }, {ODEC,  ACX,    }, {ODEC,  ADX,    }, {ODEC,  ABX,    },
  {ODEC,  ASP,    }, {ODEC,  ABP,    }, {ODEC,  ASI,    }, {ODEC,  ADI,    },
//50
  {OPUSH, AAX,    }, {OPUSH, ACX,    }, {OPUSH, ADX,    }, {OPUSH, ABX,    },
  {OPUSH, ASP,    }, {OPUSH, ABP,    }, {OPUSH, ASI,    }, {OPUSH, ADI,    },
  {OPOP,  AAX,    }, {OPOP,  ACX,    }, {OPOP,  ADX,    }, {OPOP,  ABX,    },
  {OPOP,  ASP,    }, {OPOP,  ABP,    }, {OPOP,  ASI,    }, {OPOP,  ADI,    },
//60
  {OPUSHA,        }, {OPOPA,         }, {OBOUND,AGv,AMa,AMa2}, {OARPL, AEw, AGw},
  {OSEG,  AFS,    }, {OSEG,  AGS,    }, {OOSIZE,        }, {OASIZE,        },
  {OPUSH, AIv,    }, {OIMUL,AGv,AEv,AIv},{OPUSH, AIb,   }, {OIMUL,AGv,AEv,AIb},
  {OINS,  AYb, ADX}, {OINS,  AYv, ADX}, {OOUTS, ADX, AXb}, {OOUTS, ADX, AXv},
//70
  {OJOS,  AJb,    }, {OJOC,  AJb,    }, {OJCS,  AJb,    }, {OJCC,  AJb,    },
  {OJEQ,  AJb,    }, {OJNE,  AJb,    }, {OJLS,  AJb,    }, {OJHI,  AJb,    },
  {OJMI,  AJb,    }, {OJPL,  AJb,    }, {OJPS,  AJb,    }, {OJPC,  AJb,    },
  {OJLT,  AJb,    }, {OJGE,  AJb,    }, {OJLE,  AJb,    }, {OJGT,  AJb,    },
//80
  {OGP1,  AEb, AIb}, {OGP1,  AEv, AIv}, {OGP1,  AEv, AIc}, {OGP1,  AEv, AIc},
  {OTEST, AEb, AGb}, {OTEST, AEv, AGv}, {OXCHG, AEb, AGb}, {OXCHG, AEv, AGv},
  {OMOV,  AEb, AGb}, {OMOV,  AEv, AGv}, {OMOV,  AGb, AEb}, {OMOV,  AGv, AEv},
  {OMOV,  AEw, ASw}, {OLEA,  AGv, AM }, {OMOV,  ASw, AEw}, {OPOP,  AEv,    },
//90
  {ONOP,          }, {OXCHG, AAX, ACX}, {OXCHG, AAX, ADX}, {OXCHG, AAX, ABX},
  {OXCHG, AAX, ASP}, {OXCHG, AAX, ABP}, {OXCHG, AAX, ASI}, {OXCHG, AAX, ADI},
  {OCBW,          }, {OCWD,          }, {OCALL, AAp,    }, {OWAIT,         },
  {OPUSHF,AFv,    }, {OPOPF, AFv,    }, {OSAHF, AAH,    }, {OLAHF, AAH,    },
//A0
  {OMOV,  AAL, AOb}, {OMOV,  AAX, AOv}, {OMOV,  AOb, AAL}, {OMOV,  AOv, AAX},
  {OMOVS, AXb, AYb}, {OMOVS, AXv, AYv}, {OCMPS, AXb, AYb}, {OCMPS, AXv, AYv},
  {OTEST, AAL, AIb}, {OTEST, AAX, AIv}, {OSTOS, AYb, AAL}, {OSTOS, AYv, AAX},
  {OLODS, AAL, AXb}, {OLODS, AAX, AXv}, {OSCAS, AAL, AYb}, {OSCAS, AAX, AYv},
//B0
  {OMOV,  AAL, AIb}, {OMOV,  ACL, AIb}, {OMOV,  ADL, AIb}, {OMOV,  ABL, AIb},
  {OMOV,  AAH, AIb}, {OMOV,  ACH, AIb}, {OMOV,  ADH, AIb}, {OMOV,  ABH, AIb},
  {OMOV,  AAX, AIv}, {OMOV,  ACX, AIv}, {OMOV,  ADX, AIv}, {OMOV,  ABX, AIv},
  {OMOV,  ASP, AIv}, {OMOV,  ABP, AIv}, {OMOV,  ASI, AIv}, {OMOV,  ADI, AIv},
//C0
  {OGP2,  AEb, AIb}, {OGP2,  AEv, AIb}, {ORET,  AIw,    }, {ORET,  A0,     },
  {OLFP,AES,AGv,AMp},{OLFP,ADS,AGv,AMp},{OMOV,  AEb, AIb}, {OMOV,  AEv, AIv},
  {OENTER,AIw, AIb}, {OLEAVE,        }, {ORETF, AIw,    }, {ORETF, A0,     },
  {OINT,  A3,     }, {OINT,  AIb,    }, {OINT,  A4,     }, {OIRET,         },
//D0
  {OGP2,  AEb, A1 }, {OGP2,  AEv, A1 }, {OGP2,  AEb, ACL}, {OGP2,  AEv, ACL},
  {OAAM,  AIb,    }, {OAAD,  AIb,    }, {OBAD,          }, {OXLAT, AAL, ABX},
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
//E0
  {OLOOPNZ,AJb,ACX}, {OLOOPZ,AJb, ACX}, {OLOOP, AJb, ACX}, {OJCXZ, AJb,    },
  {OIN,   AAL, AIb}, {OIN,   AAX, AIb}, {OOUT,  AIb, AAL}, {OOUT,  AIb, AAX},
  {OCALL, AJv,    }, {OJMP,  AJv,    }, {OJMP,  AAp,    }, {OJMP,  AJb,    },
  {OIN,   AAL, ADX}, {OIN,   AAX, ADX}, {OOUT,  ADX, AAL}, {OOUT,  ADX, AAX},
//F0
  {OLOCK,         }, {OBAD,          }, {OREPNZ,        }, {OREPZ,         },
  {OHLT,          }, {OCMC,          }, {OGP3b,         }, {OGP3v,         },
  {OCLC,          }, {OSTC,          }, {OCLI,          }, {OSTI,          },
  {OCLD,          }, {OSTD,          }, {OGP4,          }, {OGP5,          },
};

static Optab optab0F[256] = {
//00
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
//10 - mostly floating point and quadword moves
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
//20 - doubleword <-> control register moves, other arcana
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
//30 - wrmsr, rdtsc, rdmsr, rdpmc, sysenter, sysexit
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
//40 - conditional moves
  {OCMOVOS,AGv,AEv}, {OCMOVOC,AGv,AEv}, {OCMOVCS,AGv,AEv}, {OCMOVCC,AGv,AEv},
  {OCMOVEQ,AGv,AEv}, {OCMOVNE,AGv,AEv}, {OCMOVLS,AGv,AEv}, {OCMOVHI,AGv,AEv},
  {OCMOVMI,AGv,AEv}, {OCMOVPL,AGv,AEv}, {OCMOVPS,AGv,AEv}, {OCMOVPC,AGv,AEv},
  {OCMOVLT,AGv,AEv}, {OCMOVGE,AGv,AEv}, {OCMOVLE,AGv,AEv}, {OCMOVGT,AGv,AEv},
//50 - floating point, mmx stuff
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
//60 - floating point, mmx stuff
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
//70 - floating point, mmx stuff
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
//80 - long-displacement jumps
  {OJOS,  AJv,    }, {OJOC,  AJv,    }, {OJCS,  AJv,    }, {OJCC,  AJv,    },
  {OJEQ,  AJv,    }, {OJNE,  AJv,    }, {OJLS,  AJv,    }, {OJHI,  AJv,    },
  {OJMI,  AJv,    }, {OJPL,  AJv,    }, {OJPS,  AJv,    }, {OJPC,  AJv,    },
  {OJLT,  AJv,    }, {OJGE,  AJv,    }, {OJLE,  AJv,    }, {OJGT,  AJv,    },
//90 - conditional byte set
  {OSETOS,AEb,    }, {OSETOC,AEb,    }, {OSETCS,AEb,    }, {OSETCC,AEb,    },
  {OSETEQ,AEb,    }, {OSETNE,AEb,    }, {OSETLS,AEb,    }, {OSETHI,AEb,    },
  {OSETMI,AEb,    }, {OSETPL,AEb,    }, {OSETPS,AEb,    }, {OSETPC,AEb,    },
  {OSETLT,AEb,    }, {OSETGE,AEb,    }, {OSETLE,AEb,    }, {OSETGT,AEb,    },
//A0
  {OPUSH, AFS,    }, {OPOP,  AFS,    }, {OBAD,          }, {OBT,   AEv, AGv},
  {OSHLD,AEv,AGv,AIb}, {OSHLD,AEv,AGv,ACL}, {OBAD,      }, {OBAD,          },
  {OPUSH, AGS,    }, {OPOP,  AGS,    }, {OBAD,          }, {OBTS,  AEv, AGv},
  {OSHRD,AEv,AGv,AIb}, {OSHRD,AEv,AGv,ACL}, {OBAD,      }, {OIMUL, AGv,AGv,AEv},
//B0 - mostly arcana
  {OBAD,          }, {OBAD,          }, {OLFP,ASS,AGv,AMp},{OBAD,          },
  {OLFP,AFS,AGv,AMp},{OLFP,AGS,AGv,AMp},{OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
//C0 - more arcana
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
//D0 - mmx
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
//E0 - mmx
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
//F0 - mmx
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
};

/* some operands map to whole groups; group numbers from intel opcode map */
/* args filled in already (in OGP1 entries) */
static Optab optabgp1[8] = {
  {OADD,          }, {OOR,           }, {OADC,          }, {OSBB,          },
  {OAND,          }, {OSUB,          }, {OXOR,          }, {OCMP,          },
};

/* args filled in already (in OGP2 entries) */
static Optab optabgp2[8] = {
  {OROL,          }, {OROR,          }, {ORCL,          }, {ORCR,          },
  {OSHL,          }, {OSHR,          }, {OBAD,          }, {OSAR,          },
};

static Optab optabgp3b[8] = {
  {OTEST, AEb, AIb}, {OBAD,          }, {ONOT,  AEb,    }, {ONEG,  AEb,    },
  {OMUL,AAX,AAL,AEb},{OIMUL,AAX,AAL,AEb},{ODIV, AEb,    }, {OIDIV, AEb,    },
};

static Optab optabgp3v[8] = {
  {OTEST, AEv, AIv}, {OBAD,          }, {ONOT,  AEv,    }, {ONEG,  AEv,    },
  {OMUL,AAX,AAX,AEv},{OIMUL,AAX,AAX,AEv},{ODIV, AEv,    }, {OIDIV, AEv,    },
};

static Optab optabgp4[8] = {
  {OINC,  AEb,    }, {ODEC,  AEb,    }, {OBAD,          }, {OBAD,          },
  {OBAD,          }, {OBAD,          }, {OBAD,          }, {OBAD,          },
};

static Optab optabgp5[8] = {
  {OINC,  AEv,    }, {ODEC,  AEv,    }, {OCALL,  AEv,   }, {OCALL,  AEp    },
  {OJMP,  AEv,    }, {OJMP,  AEp,    }, {OPUSH,  AEv,   }, {OBAD,          },
};

/* optabg6  unimplemented - mostly segment manipulation */
/* optabg7 unimplemented - more segment manipulation */
/* optabg8 unimplemented - bit tests */

/*
 * most of optabg9 - optabg16 decode differently depending on the mod value of
 * the modrm byte.  they're mostly arcane instructions so they're not
 * implemented.
 */

/*
 * the above tables are in intel order, in which data moves right to left.
 * change to plan9, left to right.
 */
static void
revtab(Optab *o, int n)
{
	int i, t;

	for(i=0; i<n; i++){
		if(o[i].arg1!=ANONE && o[i].arg2!=ANONE && o[i].arg3==ANONE){
			t = o[i].arg1;
			o[i].arg1 = o[i].arg2;
			o[i].arg2 = t;
		}
	}
}
void
plan9order(void)
{
	revtab(optab, nelem(optab));
	revtab(optab0F, nelem(optab0F));
	/* revtab gp3b and gp3v? */
}

static Optab *optabgp[NUMOP] = {
[OGP1]	optabgp1,
[OGP2]	optabgp2,
[OGP3b]	optabgp3b,
[OGP3v]	optabgp3v,
[OGP4]	optabgp4,
[OGP5]	optabgp5,
};

static int
matchmodrm(Expr *e, Istate *is)
{
	/* various memory references unimplemented */
	return 0;
}

static int
isconst(Expr *e)
{
	if(e == nil)
		return 0;

	switch(e->op){
	case ENAME:
		return 1;
	case ECONST:
		return 1;
	case EMUL:
	case EADD:
	case ESUB:
		return isconst(e->arg[0]) && isconst(e->arg[1]);
	default:
		return 0;
	}
}

static int
matcharg(int a, Expr *e, Istate *is)
{
	int seg;
	int off;

	if(a==ANONE && e==nil)
		return 1;
	if(a==ANONE || e==nil)
		return 0;

	switch(a){
	case AAp:	/* seg:off immediate address */
		if(e->op==ESEG && isconst(e->arg[0]) && isconst(e->arg[1])){
			seg = e->arg[0]->con;
			is->byte[is->nbyte++] = seg;
			is->byte[is->nbyte++] = seg>>8;
			off = e->arg[0]->con;
			is->byte[is->nbyte++] = off;
			is->byte[is->nbyte++] = off>>8;
			return 1;
		}
		return 0;
	case AEb:	/* r/m8 from modrm byte */
		if(e->op==EREG && e->sz==8 && e->reg<8){
			is->mod = 3;
			is->rm = e->reg;
			is->needmodrm = 1;
			return 1;
		}
		if(e->op==EBYTE && matchmodrm(e, is))
			return 1;
		return 0;
	case AEp:	/* call indirect through memory */
		if(e->op==EADDR && matchmodrm(e, is))
			return 1;
		return 0;
	case AEw:
	case AEv:	/* r/m16 or r/m32 from modrm byte */
		if(e->op==EREG && e->sz==16 && e->reg<8){
			is->mod = 3;
			is->rm = e->reg;
			is->needmodrm = 1;
			return 1;
		}
		if(e->op==EWORD && matchmodrm(e, is))
			return 1;
		return 0;
	case AGb:	/* r8 from modrm byte */
		if(e->op==EREG && e->sz==8 && e->reg<8){
			is->rop = e->reg;
			is->needmodrm = 1;
			return 1;
		}
		return 0;
	case AGv:	/* r16 or r32 from modrm byte */
		if(e->op==EREG && e->sz==16 && e->reg<8){
			is->rop = e->reg;
			is->needmodrm = 1;
			return 1;
		}
		return 0;
	case AGw:	/* r/m 16 */
		if(e->op==EREG && e->sz==16 && e->reg<8){
			is->rop = e->reg;
			is->needmodrm = 1;
			return 1;
		}
		return 0;
	case AIb:	/* immediate byte */
		if(isconst(e) && 0x00 <= e->con && e->con <= 0xFF){
			is->consz = 1;
			is->conoff = is->nbyte;
			is->byte[is->nbyte++] = e->con;
			return 1;
		}
		return 0;
	case AIc:	/* immediate byte sign-extended */
		if(isconst(e) && -0x80 <= e->con && e->con <= 0x7F){
			is->consz = 1;
			is->conoff = is->nbyte;
			is->byte[is->nbyte++] = e->con;
			return 1;
		}
		return 0;
	case AIw:	/* immediate 16-bit word */
		if(isconst(e)){
			is->consz = 2;
			is->conoff = is->nbyte;
			is->byte[is->nbyte++] = e->con;
			is->byte[is->nbyte++] = e->con>>8;
			return 1;
		}
		return 0;
	case AIv:	/* immediate 16-bit or 32-bit word */
		if(isconst(e)){
			is->consz = 2;
			is->conoff = is->nbyte;
			is->byte[is->nbyte++] = e->con;
			is->byte[is->nbyte++] = e->con>>8;
			return 1;
		}
		return 0;
	case AJb:	/* relative offset byte */
		if(e->sz==1){
			is->jmpoff = is->nbyte++;
			return 1;
		}
		return 0;
	case AJv:	/* relative offset 16-bit or 32-bit word */
		if(e->sz==2){
			is->jmpoff = is->nbyte;
			is->nbyte += 2;
			return 1;
		}
		return 0;
	case AJr:	/* r/m16 or r/m32 register */
		if(e->op==EREG && e->sz==16 && e->reg<8){
			is->needmodrm = 1;
			is->mod = 3;
			is->rm = e->reg;
			return 1;
		}
		return 0;
	case AM:	/* memory address from modrm */
		if(e->op==EADDR && matchmodrm(e, is))
			return 1;
		return 0;
	case AMa:	/* something for bound? */
		if(e->op==EADDR && matchmodrm(e, is))
			return 1;
		return 0;
	case AMp:	/* 32-bit or 48-bit memory address */
		return e->op==EADDR && matchmodrm(e, is);
	case AOb:	/* immediate word-sized offset to a byte */
		return 0;
	case AOv:	/* immediate word-sized offset to a word */
		return 0;
	case ASw:	/* segment register selected by field of modrm */
		if(e->op==EREG && e->reg >= RES && e->reg <= RDS){
			is->needmodrm = 1;
			is->rop = e->reg - RES;
			return 1;
		}
		return 0;
	case AAL:
		return e->op==EREG && e->sz==8 && e->reg==RAL;
	case ACL:
		return e->op==EREG && e->sz==8 && e->reg==RCL;
	case ADL:
		return e->op==EREG && e->sz==8 && e->reg==RDL;
	case ABL:
		return e->op==EREG && e->sz==8 && e->reg==RBL;
	case AAH:
		return e->op==EREG && e->sz==8 && e->reg==RAH;
	case ACH:
		return e->op==EREG && e->sz==8 && e->reg==RCH;
	case ADH:
		return e->op==EREG && e->sz==8 && e->reg==RDH;
	case ABH:
		return e->op==EREG && e->sz==8 && e->reg==RBH;
	case AAX:
		return e->op==EREG && e->sz==16 && e->reg==RAX;
	case ACX:
		return e->op==EREG && e->sz==16 && e->reg==RCX;
	case ADX:
		return e->op==EREG && e->sz==16 && e->reg==RDX;
	case ABX:
		return e->op==EREG && e->sz==16 && e->reg==RBX;
	case ASP:
		return e->op==EREG && e->sz==16 && e->reg==RSP;
	case ABP:
		return e->op==EREG && e->sz==16 && e->reg==RBP;
	case ASI:
		return e->op==EREG && e->sz==16 && e->reg==RSI;
	case ADI:
		return e->op==EREG && e->sz==16 && e->reg==RDI;
	case AES:
		return e->op==EREG && e->sz==16 && e->reg==RES;
	case ACS:
		return e->op==EREG && e->sz==16 && e->reg==RCS;
	case ASS:
		return e->op==EREG && e->sz==16 && e->reg==RSS;
	case ADS:
		return e->op==EREG && e->sz==16 && e->reg==RDS;
	case AFS:
		return e->op==EREG && e->sz==16 && e->reg==RFS;
	case AGS:
		return e->op==EREG && e->sz==16 && e->reg==RGS;
	default:
		return 0;
	}
}
	
static void
match(Optab *o, int b, Inst *inst, Istate *is)
{
	uchar xb[16];
	int nxb;
	int i, modrmoff;
	Istate ts, ots;
	Optab *og;

	switch(o->op){
	case O0F:
		ots = *is;
		ots.byte[ots.nbyte++] = 0x0F;
		for(i=0; i<nelem(optab0F); i++){
			ts = ots;
			match(&optab0F[i], i, inst, &ts);
		}
		return;
	case OGP1:
	case OGP2:
	case OGP3b:
	case OGP3v:
	case OGP4:
	case OGP5:
		ots = *is;
		og = optabgp[o->op];
		for(i=0; i<8; i++){
			if(o->arg1!=ANONE)
				og[i].arg1 = o->arg1;
			if(o->arg2!=ANONE)
				og[i].arg2 = o->arg2;
			if(o->arg3!=ANONE)
				og[i].arg3 = o->arg3;
			ts = ots;
			ts.rop = i;
			ts.needmodrm = 1;
			match(&og[i], b, inst, &ts);
		}
		return;
	}

	if(o->op != inst->op)
		return;

	ts = *is;
	ts.byte[ts.nbyte++] = b;
	modrmoff = ts.nbyte;
	if(!matcharg(o->arg1, inst->arg[0], &ts))
		return;
	if(!matcharg(o->arg2, inst->arg[1], &ts))
		return;
	if(!matcharg(o->arg3, inst->arg[2], &ts))
		return;
	if(ts.needmodrm){
		nxb = ts.nbyte - modrmoff;
		memmove(xb, ts.byte+modrmoff, nxb);
		ts.nbyte = modrmoff;
		ts.byte[ts.nbyte++] = (ts.mod<<6) | (ts.rop<<3) | ts.rm;
		if(ts.mod==1)
			ts.byte[ts.nbyte++] = ts.disp;
		if((ts.mod==0 && ts.rm==6) || ts.mod==2){
			ts.byte[ts.nbyte++] = ts.disp;
			ts.byte[ts.nbyte++] = ts.disp>>8;
		}
		memmove(ts.byte+ts.nbyte, xb, nxb);
		ts.nbyte += nxb;
	}
	if(ts.nbyte < inst->nbyte)
		inst->Istate = ts;
}

static int isjmp[NUMOP] = 
{
[OJCXZ] 1,
[OJOS] 1,
[OJOC] 1,
[OJCS] 1,
[OJCC] 1,
[OJEQ] 1,
[OJNE] 1,
[OJLS] 1,
[OJHI] 1,
[OJMI] 1,
[OJPL] 1,
[OJPS] 1,
[OJPC] 1,
[OJLT] 1,
[OJGE] 1,
[OJLE] 1,
[OJGT] 1,
[OJMP] 1,
};

static uchar prefix[] = { 0xF0, 0xF2, 0xF3, 0x26, 0x2E, 0x36, 0x3E, 0x64, 0x65 };
static int
domatch(Inst *inst)
{
	int i;
	Istate ts;

	memset(&ts, 0, sizeof ts);
	for(i=0; i<inst->npref; i++)
		ts.byte[ts.nbyte++] = prefix[inst->pref[i]];

	inst->nbyte = 1000;
	for(i=0; i<nelem(optab); i++)
		match(&optab[i], i, inst, &ts);
	if(inst->nbyte == 1000)
		return -1;
	return 0;
}
int
assinst(Inst *inst)
{
/* calc both spans 
	if(isjmp[inst->op] && inst->arg[0] && inst->arg[0]->op != EREG){
		if(inst->arg[0]==nil)
			return -1;
		inst->arg[0]->sz = 1;
		if(domatch(inst) < 0)
			return -1;
		inst->span1 = inst->Istate;

		inst->arg[0]->sz = 2;
		if(domatch(inst) < 0)
			return -1;
		inst->span2 = inst->Istate;
		inst->isspan = 1;
		return 0;
	}
*/
/* punt on spans for now: */
	if(isjmp[inst->op] && isconst(inst->arg[0]))
		inst->arg[0]->sz = 2;
	if(inst->op == OLABEL){
		inst->nbyte = 0;
		return 0;
	}
	return domatch(inst);
}


Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.