Fixes for 64-bit ndisasm.

This fixes some of the most glaring bugs in ndisasm 64-bit mode.  We're
still getting redundant prefixes for unknown reason, however.
This commit is contained in:
H. Peter Anvin 2007-04-16 02:02:06 +00:00
parent 88aa185d36
commit b061d595fb
3 changed files with 60 additions and 81 deletions

View File

@ -25,8 +25,9 @@
* assembly mode or the operand-size override on the operand * assembly mode or the operand-size override on the operand
* \37 - a word constant, from the _segment_ part of operand 0 * \37 - a word constant, from the _segment_ part of operand 0
* \40, \41, \42 - a long immediate operand, from operand 0, 1 or 2 * \40, \41, \42 - a long immediate operand, from operand 0, 1 or 2
* \44, \45, \46 - select between \3[012] and \4[012] depending on 16/32 bit * \44, \45, \46 - select between \3[012], \4[012] and \5[456]
* assembly mode or the address-size override on the operand * depending on assembly mode or the address-size override
* on the operand.
* \50, \51, \52 - a byte relative operand, from operand 0, 1 or 2 * \50, \51, \52 - a byte relative operand, from operand 0, 1 or 2
* \54, \55, \56 - a qword immediate operand, from operand 0, 1 or 2 * \54, \55, \56 - a qword immediate operand, from operand 0, 1 or 2
* \60, \61, \62 - a word relative operand, from operand 0, 1 or 2 * \60, \61, \62 - a word relative operand, from operand 0, 1 or 2

134
disasm.c
View File

@ -122,6 +122,8 @@ static int whichreg(int32_t regflags, int regval, int rex)
return rd_reg16[regval]; return rd_reg16[regval];
if (!((REGMEM | BITS32) & ~regflags)) if (!((REGMEM | BITS32) & ~regflags))
return rd_reg32[regval]; return rd_reg32[regval];
if (!((REGMEM | BITS64) & ~regflags))
return rd_reg64[regval];
if (!(REG_SREG & ~regflags)) if (!(REG_SREG & ~regflags))
return rd_sreg[regval & 7]; /* Ignore REX */ return rd_sreg[regval & 7]; /* Ignore REX */
if (!(REG_CREG & ~regflags)) if (!(REG_CREG & ~regflags))
@ -338,12 +340,13 @@ static int matches(struct itemplate *t, uint8_t *data, int asize,
while (*r) { while (*r) {
int c = *r++; int c = *r++;
if (c >= 01 && c <= 03) {
/* FIX: change this into a switch */
if (c >= 01 && c <= 03) {
while (c--) while (c--)
if (*r++ != *data++) if (*r++ != *data++)
return FALSE; return FALSE;
} } else if (c == 04) {
if (c == 04) {
switch (*data++) { switch (*data++) {
case 0x07: case 0x07:
ins->oprs[0].basereg = 0; ins->oprs[0].basereg = 0;
@ -357,8 +360,7 @@ static int matches(struct itemplate *t, uint8_t *data, int asize,
default: default:
return FALSE; return FALSE;
} }
} } else if (c == 05) {
if (c == 05) {
switch (*data++) { switch (*data++) {
case 0xA1: case 0xA1:
ins->oprs[0].basereg = 4; ins->oprs[0].basereg = 4;
@ -368,9 +370,8 @@ static int matches(struct itemplate *t, uint8_t *data, int asize,
break; break;
default: default:
return FALSE; return FALSE;
} }
} } else if (c == 06) {
if (c == 06) {
switch (*data++) { switch (*data++) {
case 0x06: case 0x06:
ins->oprs[0].basereg = 0; ins->oprs[0].basereg = 0;
@ -387,8 +388,7 @@ static int matches(struct itemplate *t, uint8_t *data, int asize,
default: default:
return FALSE; return FALSE;
} }
} } else if (c == 07) {
if (c == 07) {
switch (*data++) { switch (*data++) {
case 0xA0: case 0xA0:
ins->oprs[0].basereg = 4; ins->oprs[0].basereg = 4;
@ -399,32 +399,28 @@ static int matches(struct itemplate *t, uint8_t *data, int asize,
default: default:
return FALSE; return FALSE;
} }
} } else if (c >= 010 && c <= 012) {
if (c >= 010 && c <= 012) {
int t = *r++, d = *data++; int t = *r++, d = *data++;
if (d < t || d > t + 7) if (d < t || d > t + 7)
return FALSE; return FALSE;
else { else {
ins->oprs[c - 010].basereg = d - t; ins->oprs[c - 010].basereg = (d-t)+(rex & REX_B ? 8 : 0);
ins->oprs[c - 010].segment |= SEG_RMREG; ins->oprs[c - 010].segment |= SEG_RMREG;
} }
} } else if (c == 017) {
if (c == 017)
if (*data++) if (*data++)
return FALSE; return FALSE;
if (c >= 014 && c <= 016) { } else if (c >= 014 && c <= 016) {
ins->oprs[c - 014].offset = (int8_t)*data++; ins->oprs[c - 014].offset = (int8_t)*data++;
ins->oprs[c - 014].segment |= SEG_SIGNED; ins->oprs[c - 014].segment |= SEG_SIGNED;
} } else if (c >= 020 && c <= 022) {
if (c >= 020 && c <= 022)
ins->oprs[c - 020].offset = *data++; ins->oprs[c - 020].offset = *data++;
if (c >= 024 && c <= 026) } else if (c >= 024 && c <= 026) {
ins->oprs[c - 024].offset = *data++; ins->oprs[c - 024].offset = *data++;
if (c >= 030 && c <= 032) { } else if (c >= 030 && c <= 032) {
ins->oprs[c - 030].offset = getu16(data); ins->oprs[c - 030].offset = getu16(data);
data += 2; data += 2;
} } else if (c >= 034 && c <= 036) {
if (c >= 034 && c <= 036) {
if (osize == 32) { if (osize == 32) {
ins->oprs[c - 034].offset = getu32(data); ins->oprs[c - 034].offset = getu32(data);
data += 4; data += 4;
@ -434,38 +430,38 @@ static int matches(struct itemplate *t, uint8_t *data, int asize,
} }
if (segsize != asize) if (segsize != asize)
ins->oprs[c - 034].addr_size = asize; ins->oprs[c - 034].addr_size = asize;
} } else if (c >= 040 && c <= 042) {
if (c >= 040 && c <= 042) {
ins->oprs[c - 040].offset = getu32(data); ins->oprs[c - 040].offset = getu32(data);
data += 4; data += 4;
} } else if (c >= 044 && c <= 046) {
if (c >= 044 && c <= 046) { switch (asize) {
/* hpa: should this be gets32/gets16? */ case 16:
if (asize == 32) {
ins->oprs[c - 044].offset = getu32(data);
data += 4;
} else {
ins->oprs[c - 044].offset = getu16(data); ins->oprs[c - 044].offset = getu16(data);
data += 2; data += 2;
break;
case 32:
ins->oprs[c - 044].offset = getu32(data);
data += 4;
break;
case 64:
ins->oprs[c - 044].offset = getu64(data);
data += 8;
break;
} }
if (segsize != asize) if (segsize != asize)
ins->oprs[c - 044].addr_size = asize; ins->oprs[c - 044].addr_size = asize;
} } else if (c >= 050 && c <= 052) {
if (c >= 050 && c <= 052) {
ins->oprs[c - 050].offset = gets8(data++); ins->oprs[c - 050].offset = gets8(data++);
ins->oprs[c - 050].segment |= SEG_RELATIVE; ins->oprs[c - 050].segment |= SEG_RELATIVE;
} } else if (c >= 054 && c <= 056) {
if (c >= 054 && c <= 056) {
ins->oprs[c - 054].offset = getu64(data); ins->oprs[c - 054].offset = getu64(data);
data += 8; data += 8;
} } else if (c >= 060 && c <= 062) {
if (c >= 060 && c <= 062) {
ins->oprs[c - 060].offset = gets16(data); ins->oprs[c - 060].offset = gets16(data);
data += 2; data += 2;
ins->oprs[c - 060].segment |= SEG_RELATIVE; ins->oprs[c - 060].segment |= SEG_RELATIVE;
ins->oprs[c - 060].segment &= ~SEG_32BIT; ins->oprs[c - 060].segment &= ~SEG_32BIT;
} } else if (c >= 064 && c <= 066) {
if (c >= 064 && c <= 066) {
if (osize == 32) { if (osize == 32) {
ins->oprs[c - 064].offset = getu32(data); ins->oprs[c - 064].offset = getu32(data);
data += 4; data += 4;
@ -480,101 +476,83 @@ static int matches(struct itemplate *t, uint8_t *data, int asize,
(ins->oprs[c - 064].type & NON_SIZE) (ins->oprs[c - 064].type & NON_SIZE)
| ((osize == 16) ? BITS16 : BITS32); | ((osize == 16) ? BITS16 : BITS32);
} }
} } else if (c >= 070 && c <= 072) {
if (c >= 070 && c <= 072) {
ins->oprs[c - 070].offset = getu32(data); ins->oprs[c - 070].offset = getu32(data);
data += 4; data += 4;
ins->oprs[c - 070].segment |= SEG_32BIT | SEG_RELATIVE; ins->oprs[c - 070].segment |= SEG_32BIT | SEG_RELATIVE;
} } else if (c >= 0100 && c < 0130) {
if (c >= 0100 && c < 0130) {
int modrm = *data++; int modrm = *data++;
ins->oprs[c & 07].basereg = (modrm >> 3) & 07; ins->oprs[c & 07].basereg = ((modrm >> 3)&7)+(rex & REX_R ? 8 : 0);
ins->oprs[c & 07].segment |= SEG_RMREG; ins->oprs[c & 07].segment |= SEG_RMREG;
data = do_ea(data, modrm, asize, segsize, data = do_ea(data, modrm, asize, segsize,
&ins->oprs[(c >> 3) & 07], rex); &ins->oprs[(c >> 3) & 07], rex);
} } else if (c >= 0130 && c <= 0132) {
if (c >= 0130 && c <= 0132) {
ins->oprs[c - 0130].offset = getu16(data); ins->oprs[c - 0130].offset = getu16(data);
data += 2; data += 2;
} } else if (c >= 0140 && c <= 0142) {
if (c >= 0140 && c <= 0142) {
ins->oprs[c - 0140].offset = getu32(data); ins->oprs[c - 0140].offset = getu32(data);
data += 4; data += 4;
} } else if (c >= 0200 && c <= 0277) {
if (c >= 0200 && c <= 0277) {
int modrm = *data++; int modrm = *data++;
if (((modrm >> 3) & 07) != (c & 07)) if (((modrm >> 3) & 07) != (c & 07))
return FALSE; /* spare field doesn't match up */ return FALSE; /* spare field doesn't match up */
data = do_ea(data, modrm, asize, segsize, data = do_ea(data, modrm, asize, segsize,
&ins->oprs[(c >> 3) & 07], rex); &ins->oprs[(c >> 3) & 07], rex);
} } else if (c >= 0300 && c <= 0302) {
if (c >= 0300 && c <= 0302) {
if (asize) if (asize)
ins->oprs[c - 0300].segment |= SEG_32BIT; ins->oprs[c - 0300].segment |= SEG_32BIT;
else else
ins->oprs[c - 0300].segment &= ~SEG_32BIT; ins->oprs[c - 0300].segment &= ~SEG_32BIT;
a_used = TRUE; a_used = TRUE;
} } else if (c == 0310) {
if (c == 0310) {
if (asize != 16) if (asize != 16)
return FALSE; return FALSE;
else else
a_used = TRUE; a_used = TRUE;
} } else if (c == 0311) {
if (c == 0311) {
if (asize == 16) if (asize == 16)
return FALSE; return FALSE;
else else
a_used = TRUE; a_used = TRUE;
} } else if (c == 0312) {
if (c == 0312) {
if (asize != segsize) if (asize != segsize)
return FALSE; return FALSE;
else else
a_used = TRUE; a_used = TRUE;
} } else if (c == 0320) {
if (c == 0320) {
if (osize != 16) if (osize != 16)
return FALSE; return FALSE;
else else
o_used = TRUE; o_used = TRUE;
} } else if (c == 0321) {
if (c == 0321) { if (osize != 32)
if (osize == 16)
return FALSE; return FALSE;
else else
o_used = TRUE; o_used = TRUE;
} } else if (c == 0322) {
if (c == 0322) {
if (osize != (segsize == 16) ? 16 : 32) if (osize != (segsize == 16) ? 16 : 32)
return FALSE; return FALSE;
else else
o_used = TRUE; o_used = TRUE;
} } else if (c == 0323) {
if (c == 0323) {
rex |= REX_W; /* 64-bit only instruction */ rex |= REX_W; /* 64-bit only instruction */
osize = 64; osize = 64;
} } else if (c == 0324) {
if (c == 0324) { if (!(rex & REX_P) || osize != 64)
if (!(rex & REX_P))
return FALSE; return FALSE;
} } else if (c == 0330) {
if (c == 0330) {
int t = *r++, d = *data++; int t = *r++, d = *data++;
if (d < t || d > t + 15) if (d < t || d > t + 15)
return FALSE; return FALSE;
else else
ins->condition = d - t; ins->condition = d - t;
} } else if (c == 0331) {
if (c == 0331) {
if (rep) if (rep)
return FALSE; return FALSE;
} } else if (c == 0332) {
if (c == 0332) {
if (drep == P_REP) if (drep == P_REP)
drep = P_REPE; drep = P_REPE;
} } else if (c == 0333) {
if (c == 0333) {
if (rep != 0xF3) if (rep != 0xF3)
return FALSE; return FALSE;
drep = 0; drep = 0;

View File

@ -708,7 +708,7 @@ MOV reg64,reg64 \321\1\x8B\110 X64
MOV reg8,imm \10\xB0\21 8086,SM MOV reg8,imm \10\xB0\21 8086,SM
MOV reg16,imm \320\10\xB8\31 8086,SM MOV reg16,imm \320\10\xB8\31 8086,SM
MOV reg32,imm \321\10\xB8\41 386,SM MOV reg32,imm \321\10\xB8\41 386,SM
MOV reg64,imm \321\10\xB8\55 X64,SM MOV reg64,imm \324\10\xB8\55 X64,SM
MOV rm8,imm \300\1\xC6\200\21 8086,SM MOV rm8,imm \300\1\xC6\200\21 8086,SM
MOV rm16,imm \320\300\1\xC7\200\31 8086,SM MOV rm16,imm \320\300\1\xC7\200\31 8086,SM
MOV rm32,imm \321\300\1\xC7\200\41 386,SM MOV rm32,imm \321\300\1\xC7\200\41 386,SM