summaryrefslogtreecommitdiff
path: root/disasm.c
diff options
context:
space:
mode:
Diffstat (limited to 'disasm.c')
-rw-r--r--disasm.c121
1 files changed, 64 insertions, 57 deletions
diff --git a/disasm.c b/disasm.c
index 6320852..46cec8a 100644
--- a/disasm.c
+++ b/disasm.c
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 1996-2010 The NASM Authors - All Rights Reserved
+ * Copyright 1996-2012 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
@@ -197,28 +197,11 @@ static enum reg_enum whichreg(opflags_t regflags, int regval, int rex)
}
/*
- * Process a DREX suffix
- */
-static uint8_t *do_drex(uint8_t *data, insn *ins)
-{
- uint8_t drex = *data++;
- operand *dst = &ins->oprs[ins->drexdst];
-
- if ((drex & 8) != ((ins->rex & REX_OC) ? 8 : 0))
- return NULL; /* OC0 mismatch */
- ins->rex = (ins->rex & ~7) | (drex & 7);
-
- dst->segment = SEG_RMREG;
- dst->basereg = drex >> 4;
- return data;
-}
-
-
-/*
* Process an effective address (ModRM) specification.
*/
static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
- int segsize, operand * op, insn *ins)
+ int segsize, enum ea_type type,
+ operand *op, insn *ins)
{
int mod, rm, scale, index, base;
int rex;
@@ -227,14 +210,9 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
mod = (modrm >> 6) & 03;
rm = modrm & 07;
- if (mod != 3 && rm == 4 && asize != 16)
+ if (mod != 3 && asize != 16 && rm == 4)
sib = *data++;
- if (ins->rex & REX_D) {
- data = do_drex(data, ins);
- if (!data)
- return NULL;
- }
rex = ins->rex;
if (mod == 3) { /* pure register version */
@@ -253,6 +231,10 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
* Exception: mod=0,rm=6 does not specify [BP] as one might
* expect, but instead specifies [disp16].
*/
+
+ if (type != EA_SCALAR)
+ return NULL;
+
op->indexreg = op->basereg = -1;
op->scale = 1; /* always, in 16 bits */
switch (rm) {
@@ -341,6 +323,7 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
mod = 2; /* fake disp32 */
}
+
if (rm == 4) { /* process SIB */
scale = (sib >> 6) & 03;
index = (sib >> 3) & 07;
@@ -348,9 +331,13 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
op->scale = 1 << scale;
- if (index == 4 && !(rex & REX_X))
+ if (type == EA_XMMVSIB)
+ op->indexreg = nasm_rd_xmmreg[index | ((rex & REX_X) ? 8 : 0)];
+ else if (type == EA_YMMVSIB)
+ op->indexreg = nasm_rd_ymmreg[index | ((rex & REX_X) ? 8 : 0)];
+ else if (index == 4 && !(rex & REX_X))
op->indexreg = -1; /* ESP/RSP cannot be an index */
- else if (a64)
+ else if (a64)
op->indexreg = nasm_rd_reg64[index | ((rex & REX_X) ? 8 : 0)];
else
op->indexreg = nasm_rd_reg32[index | ((rex & REX_X) ? 8 : 0)];
@@ -365,6 +352,9 @@ static uint8_t *do_ea(uint8_t *data, int modrm, int asize,
if (segsize == 16)
op->disp_size = 32;
+ } else if (type != EA_SCALAR) {
+ /* Can't have VSIB without SIB */
+ return NULL;
}
switch (mod) {
@@ -410,6 +400,7 @@ static int matches(const struct itemplate *t, uint8_t *data,
int s_field_for = -1; /* No 144/154 series code encountered */
bool vex_ok = false;
int regmask = (segsize == 64) ? 15 : 7;
+ enum ea_type eat = EA_SCALAR;
for (i = 0; i < MAX_OPERANDS; i++) {
ins->oprs[i].segment = ins->oprs[i].disp_size =
@@ -573,7 +564,7 @@ static int matches(const struct itemplate *t, uint8_t *data,
{
int modrm = *data++;
opx->segment |= SEG_RMREG;
- data = do_ea(data, modrm, asize, segsize, opy, ins);
+ data = do_ea(data, modrm, asize, segsize, eat, opy, ins);
if (!data)
return false;
opx->basereg = ((modrm >> 3) & 7) + (ins->rex & REX_R ? 8 : 0);
@@ -607,22 +598,6 @@ static int matches(const struct itemplate *t, uint8_t *data,
}
break;
- case4(0160):
- ins->rex |= REX_D;
- ins->drexdst = op1;
- break;
-
- case4(0164):
- ins->rex |= REX_D|REX_OC;
- ins->drexdst = op1;
- break;
-
- case 0171:
- data = do_drex(data, ins);
- if (!data)
- return false;
- break;
-
case 0172:
{
uint8_t ximm = *data++;
@@ -646,13 +621,12 @@ static int matches(const struct itemplate *t, uint8_t *data,
}
break;
- case 0174:
+ case4(0174):
{
uint8_t ximm = *data++;
- c = *r++;
- ins->oprs[c].basereg = (ximm >> 4) & regmask;
- ins->oprs[c].segment |= SEG_RMREG;
+ opx->basereg = (ximm >> 4) & regmask;
+ opx->segment |= SEG_RMREG;
}
break;
@@ -668,7 +642,7 @@ static int matches(const struct itemplate *t, uint8_t *data,
int modrm = *data++;
if (((modrm >> 3) & 07) != (c & 07))
return false; /* spare field doesn't match up */
- data = do_ea(data, modrm, asize, segsize, opy, ins);
+ data = do_ea(data, modrm, asize, segsize, eat, opy, ins);
if (!data)
return false;
break;
@@ -691,7 +665,7 @@ static int matches(const struct itemplate *t, uint8_t *data,
int vexwlp = *r++;
ins->rex |= REX_V;
- if ((prefix->rex & (REX_V|REX_D|REX_P)) != REX_V)
+ if ((prefix->rex & (REX_V|REX_P)) != REX_V)
return false;
if ((vexm & 0x1f) != prefix->vex_m)
@@ -729,6 +703,27 @@ static int matches(const struct itemplate *t, uint8_t *data,
break;
}
+ case 0271:
+ if (prefix->rep == 0xF3)
+ drep = P_XRELEASE;
+ break;
+
+ case 0272:
+ if (prefix->rep == 0xF2)
+ drep = P_XACQUIRE;
+ else if (prefix->rep == 0xF3)
+ drep = P_XRELEASE;
+ break;
+
+ case 0273:
+ if (prefix->lock == 0xF0) {
+ if (prefix->rep == 0xF2)
+ drep = P_XACQUIRE;
+ else if (prefix->rep == 0xF3)
+ drep = P_XRELEASE;
+ }
+ break;
+
case 0310:
if (asize != 16)
return false;
@@ -915,6 +910,18 @@ static int matches(const struct itemplate *t, uint8_t *data,
a_used = true;
break;
+ case 0370:
+ case 0371:
+ break;
+
+ case 0374:
+ eat = EA_XMMVSIB;
+ break;
+
+ case 0375:
+ eat = EA_YMMVSIB;
+ break;
+
default:
return false; /* Unknown code */
}
@@ -923,8 +930,8 @@ static int matches(const struct itemplate *t, uint8_t *data,
if (!vex_ok && (ins->rex & REX_V))
return false;
- /* REX cannot be combined with DREX or VEX */
- if ((ins->rex & (REX_D|REX_V)) && (prefix->rex & REX_P))
+ /* REX cannot be combined with VEX */
+ if ((ins->rex & REX_V) && (prefix->rex & REX_P))
return false;
/*
@@ -936,14 +943,14 @@ static int matches(const struct itemplate *t, uint8_t *data,
}
if (lock) {
- if (ins->prefixes[PPS_LREP])
+ if (ins->prefixes[PPS_LOCK])
return false;
- ins->prefixes[PPS_LREP] = P_LOCK;
+ ins->prefixes[PPS_LOCK] = P_LOCK;
}
if (drep) {
- if (ins->prefixes[PPS_LREP])
+ if (ins->prefixes[PPS_REP])
return false;
- ins->prefixes[PPS_LREP] = drep;
+ ins->prefixes[PPS_REP] = drep;
}
ins->prefixes[PPS_WAIT] = dwait;
if (!o_used) {