/* ----------------------------------------------------------------------- *
*
- * 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.
*
/* Important: regval must already have been adjusted for rex extensions */
static enum reg_enum whichreg(opflags_t regflags, int regval, int rex)
{
+ size_t i;
+
+ static const struct {
+ opflags_t flags;
+ enum reg_enum reg;
+ } specific_registers[] = {
+ {REG_AL, R_AL},
+ {REG_AX, R_AX},
+ {REG_EAX, R_EAX},
+ {REG_RAX, R_RAX},
+ {REG_DL, R_DL},
+ {REG_DX, R_DX},
+ {REG_EDX, R_EDX},
+ {REG_RDX, R_RDX},
+ {REG_CL, R_CL},
+ {REG_CX, R_CX},
+ {REG_ECX, R_ECX},
+ {REG_RCX, R_RCX},
+ {FPU0, R_ST0},
+ {XMM0, R_XMM0},
+ {YMM0, R_YMM0},
+ {REG_ES, R_ES},
+ {REG_CS, R_CS},
+ {REG_SS, R_SS},
+ {REG_DS, R_DS},
+ {REG_FS, R_FS},
+ {REG_GS, R_GS}
+ };
+
if (!(regflags & (REGISTER|REGMEM)))
return 0; /* Registers not permissible?! */
regflags |= REGISTER;
- if (!(REG_AL & ~regflags))
- return R_AL;
- if (!(REG_AX & ~regflags))
- return R_AX;
- if (!(REG_EAX & ~regflags))
- return R_EAX;
- if (!(REG_RAX & ~regflags))
- return R_RAX;
- if (!(REG_DL & ~regflags))
- return R_DL;
- if (!(REG_DX & ~regflags))
- return R_DX;
- if (!(REG_EDX & ~regflags))
- return R_EDX;
- if (!(REG_RDX & ~regflags))
- return R_RDX;
- if (!(REG_CL & ~regflags))
- return R_CL;
- if (!(REG_CX & ~regflags))
- return R_CX;
- if (!(REG_ECX & ~regflags))
- return R_ECX;
- if (!(REG_RCX & ~regflags))
- return R_RCX;
- if (!(FPU0 & ~regflags))
- return R_ST0;
- if (!(XMM0 & ~regflags))
- return R_XMM0;
- if (!(YMM0 & ~regflags))
- return R_YMM0;
- if (!(REG_CS & ~regflags))
- return (regval == 1) ? R_CS : 0;
- if (!(REG_DESS & ~regflags))
- return (regval == 0 || regval == 2
- || regval == 3 ? nasm_rd_sreg[regval] : 0);
- if (!(REG_FSGS & ~regflags))
- return (regval == 4 || regval == 5 ? nasm_rd_sreg[regval] : 0);
- if (!(REG_SEG67 & ~regflags))
- return (regval == 6 || regval == 7 ? nasm_rd_sreg[regval] : 0);
+ for (i = 0; i < ARRAY_SIZE(specific_registers); i++)
+ if (!(specific_registers[i].flags & ~regflags))
+ return specific_registers[i].reg;
/* All the entries below look up regval in an 16-entry array */
if (regval < 0 || regval > 15)
}
/*
- * 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,
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 */
op->scale = 1 << scale;
- if (index == 4 && !(rex & REX_X))
- op->indexreg = -1; /* ESP/RSP cannot be an index */
- else if (type == EA_XMMVSIB)
+ 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 (type == EA_ZMMVSIB)
+ op->indexreg = nasm_rd_zmmreg[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)
op->indexreg = nasm_rd_reg64[index | ((rex & REX_X) ? 8 : 0)];
else
int op1, op2;
struct operand *opx, *opy;
uint8_t opex = 0;
- 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;
break;
}
- case4(014):
case4(0274):
opx->offset = (int8_t)*data++;
opx->segment |= SEG_SIGNED;
break;
case4(040):
- case4(0254):
opx->offset = getu32(data);
data += 4;
break;
+ case4(0254):
+ opx->offset = gets32(data);
+ data += 4;
+ break;
+
case4(044):
switch (asize) {
case 16:
opx->segment &= ~SEG_32BIT;
break;
- case4(064):
+ case4(064): /* rel */
opx->segment |= SEG_RELATIVE;
- if (osize == 16) {
- opx->offset = gets16(data);
- data += 2;
- opx->segment &= ~(SEG_32BIT|SEG_64BIT);
- } else if (osize == 32) {
- opx->offset = gets32(data);
- data += 4;
- opx->segment &= ~SEG_64BIT;
- opx->segment |= SEG_32BIT;
- }
- if (segsize != osize) {
- opx->type =
- (opx->type & ~SIZE_MASK)
- | ((osize == 16) ? BITS16 : BITS32);
+ /* In long mode rel is always 32 bits, sign extended. */
+ if (segsize == 64 || osize == 32) {
+ opx->offset = gets32(data);
+ data += 4;
+ if (segsize != 64)
+ opx->segment |= SEG_32BIT;
+ opx->type = (opx->type & ~SIZE_MASK)
+ | (segsize == 64 ? BITS64 : BITS32);
+ } else {
+ opx->offset = gets16(data);
+ data += 2;
+ opx->segment &= ~SEG_32BIT;
+ opx->type = (opx->type & ~SIZE_MASK) | BITS16;
}
break;
break;
}
- case4(0140):
- if (s_field_for == op1) {
- opx->offset = gets8(data);
- data++;
- } else {
- opx->offset = getu16(data);
- data += 2;
- }
- break;
-
- case4(0144):
- case4(0154):
- s_field_for = (*data & 0x02) ? op1 : -1;
- if ((*data++ & ~0x02) != *r++)
- return false;
- break;
-
- case4(0150):
- if (s_field_for == op1) {
- opx->offset = gets8(data);
- data++;
- } else {
- opx->offset = getu32(data);
- data += 4;
- }
- 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++;
}
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;
break;
}
- case4(0250):
- if (s_field_for == op1) {
- opx->offset = gets8(data);
- data++;
- } else {
- opx->offset = gets32(data);
- data += 4;
- }
- break;
-
case4(0260):
case 0270:
{
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)
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;
break;
}
+ case 0326:
+ if (prefix->rep == 0xF3)
+ return false;
+ break;
+
case 0331:
if (prefix->rep)
return false;
dwait = 0;
break;
- case4(0344):
- ins->oprs[0].basereg = (*data++ >> 3) & 7;
- break;
-
case 0360:
if (prefix->osp || prefix->rep)
return false;
o_used = true;
break;
- case 0362:
- if (prefix->osp || prefix->rep != 0xf2)
- return false;
- drep = 0;
- break;
-
- case 0363:
- if (prefix->osp || prefix->rep != 0xf3)
- return false;
- drep = 0;
- break;
-
case 0364:
if (prefix->osp)
return false;
a_used = true;
break;
+ case 0370:
+ case 0371:
+ break;
+
case 0374:
eat = EA_XMMVSIB;
break;
eat = EA_YMMVSIB;
break;
+ case 0376:
+ eat = EA_ZMMVSIB;
+ break;
+
default:
return false; /* Unknown code */
}
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;
/*
}
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) {
};
int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize,
- int32_t offset, int autosync, uint32_t prefer)
+ int32_t offset, int autosync, iflags_t prefer)
{
const struct itemplate * const *p, * const *best_p;
const struct disasm_index *ix;
uint8_t *origdata;
int works;
insn tmp_ins, ins;
- uint32_t goodness, best;
+ iflags_t goodness, best;
int best_pref;
struct prefix_info prefix;
bool end_prefix;
* XXX: Need to make sure this is actually correct.
*/
for (i = 0; i < (*p)->operands; i++) {
- if (!((*p)->opd[i] & SAME_AS) &&
- (
+ if (
/* If it's a mem-only EA but we have a
register, die. */
((tmp_ins.oprs[i].segment & SEG_RMREG) &&
(tmp_ins.oprs[i].segment & SEG_RMREG)) &&
!whichreg((*p)->opd[i],
tmp_ins.oprs[i].basereg, tmp_ins.rex))
- )) {
+ ) {
works = false;
break;
}
const operand *o = &ins.oprs[i];
int64_t offs;
- if (t & SAME_AS) {
- o = &ins.oprs[t & ~SAME_AS];
- t = (*p)->opd[t & ~SAME_AS];
- }
-
output[slen++] = (colon ? ':' : i == 0 ? ' ' : ',');
offs = o->offset;
if (t & BITS256)
slen +=
snprintf(output + slen, outbufsize - slen, "yword ");
+ if (t & BITS512)
+ slen +=
+ snprintf(output + slen, outbufsize - slen, "zword ");
if (t & FAR)
slen += snprintf(output + slen, outbufsize - slen, "far ");
if (t & NEAR)