summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-07-25 18:15:28 -0700
committerH. Peter Anvin <hpa@zytor.com>2009-07-25 18:15:28 -0700
commita81655bffb3841a0326c7224403f8c8e7cccd82a (patch)
tree0d3f2da0698d2c8967b755c47416e0f6f2c9e4dc
parent23595f5946bc816185204302a78d8413ed59cc4b (diff)
downloadnasm-a81655bffb3841a0326c7224403f8c8e7cccd82a.tar.gz
Enable fuzzy matching of operand sizes
This allows automatic fuzzy matching of operand sizes. If an operand size is not specified, but there is exactly one possible size for the instruction, select that instruction size. This requires a second pass through the instruction patterns, and so is slightly slower, but should be a lot easier to get right than the S- flags, and works even when there is more than one instruction. The new SX (Size eXact) flag can be used to prevent fuzzy matching completely. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--assemble.c49
-rw-r--r--insns.h25
2 files changed, 60 insertions, 14 deletions
diff --git a/assemble.c b/assemble.c
index e5df7282..829cb1be 100644
--- a/assemble.c
+++ b/assemble.c
@@ -1983,6 +1983,12 @@ static enum match_result find_match(const struct itemplate **tempp,
{
const struct itemplate *temp;
enum match_result m, merr;
+ int32_t xsizeflags[MAX_OPERANDS];
+ bool opsizemissing = false;
+ int i;
+
+ for (i = 0; i < instruction->operands; i++)
+ xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
merr = MERR_INVALOP;
@@ -1994,13 +2000,51 @@ static enum match_result find_match(const struct itemplate **tempp,
m = MOK_GOOD;
else
m = MERR_INVALOP;
+ } else if (m == MERR_OPSIZEMISSING &&
+ (temp->flags & IF_SMASK) != IF_SX) {
+ /*
+ * Missing operand size and a candidate for fuzzy matching...
+ */
+ for (i = 0; i < temp->operands; i++)
+ xsizeflags[i] |= temp->opd[i] & SIZE_MASK;
+
+ opsizemissing = true;
}
if (m > merr)
merr = m;
if (merr == MOK_GOOD)
- break;
+ goto done;
+ }
+
+ /* No match, but see if we can get a fuzzy operand size match... */
+ if (!opsizemissing)
+ goto done;
+
+ for (i = 0; i < instruction->operands; i++) {
+ /* This tests if xsizeflags[i] has more than one bit set */
+ if ((xsizeflags[i] & (xsizeflags[i]-1)))
+ goto done; /* No luck */
+
+ instruction->oprs[i].type |= xsizeflags[i]; /* Set the size */
+ }
+
+ /* Try matching again... */
+ for (temp = nasm_instructions[instruction->opcode];
+ temp->opcode != I_none; temp++) {
+ m = matches(temp, instruction, bits);
+ if (m == MOK_JUMP) {
+ if (jmp_match(segment, offset, bits, instruction, temp->code))
+ m = MOK_GOOD;
+ else
+ m = MERR_INVALOP;
+ }
+ if (m > merr)
+ merr = m;
+ if (merr == MOK_GOOD)
+ goto done;
}
+done:
*tempp = temp;
return merr;
}
@@ -2131,8 +2175,7 @@ static enum match_result matches(const struct itemplate *itemp,
} else if (itemp->opd[i] & ~type ||
((itemp->opd[i] & SIZE_MASK) &&
((itemp->opd[i] ^ type) & SIZE_MASK))) {
- if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
- (type & SIZE_MASK))
+ if ((itemp->opd[i] & ~type & ~SIZE_MASK) || (type & SIZE_MASK))
return MERR_INVALOP;
else
return MERR_OPSIZEMISSING;
diff --git a/insns.h b/insns.h
index e8096a73..4ae2499c 100644
--- a/insns.h
+++ b/insns.h
@@ -77,17 +77,20 @@ extern const uint8_t nasm_bytecodes[];
#define IF_SQ 0x00000010UL /* unsized operands can't be non-qword */
#define IF_SO 0x00000014UL /* unsized operands can't be non-oword */
#define IF_SY 0x00000018UL /* unsized operands can't be non-yword */
-#define IF_SZ 0x0000001CUL /* unsized operands must match the bitsize */
-#define IF_SMASK 0x0000001CUL /* mask for unsized argument size */
-#define IF_AR0 0x00000020UL /* SB, SW, SD applies to argument 0 */
-#define IF_AR1 0x00000040UL /* SB, SW, SD applies to argument 1 */
-#define IF_AR2 0x00000060UL /* SB, SW, SD applies to argument 2 */
-#define IF_AR3 0x00000080UL /* SB, SW, SD applies to argument 3 */
-#define IF_ARMASK 0x000000E0UL /* mask for unsized argument spec */
-#define IF_ARSHFT 5 /* LSB in IF_ARMASK */
-#define IF_PRIV 0x00000100UL /* it's a privileged instruction */
-#define IF_SMM 0x00000200UL /* it's only valid in SMM */
-#define IF_PROT 0x00000400UL /* it's protected mode only */
+#define IF_SZ 0x00000038UL /* unsized operands must match the bitsize */
+#define IF_SX 0x0000003CUL /* unsized operands not allowed */
+#define IF_SMASK 0x0000003CUL /* mask for unsized argument size */
+#define IF_AR0 0x00000040UL /* SB, SW, SD applies to argument 0 */
+#define IF_AR1 0x00000080UL /* SB, SW, SD applies to argument 1 */
+#define IF_AR2 0x000000C0UL /* SB, SW, SD applies to argument 2 */
+#define IF_AR3 0x00000100UL /* SB, SW, SD applies to argument 3 */
+#define IF_AR4 0x00000140UL /* SB, SW, SD applies to argument 4 */
+#define IF_ARMASK 0x000001C0UL /* mask for unsized argument spec */
+#define IF_ARSHFT 6 /* LSB in IF_ARMASK */
+/* The next 3 bits aren't actually used for anything */
+#define IF_PRIV 0x00000000UL /* it's a privileged instruction */
+#define IF_SMM 0x00000000UL /* it's only valid in SMM */
+#define IF_PROT 0x00000000UL /* it's protected mode only */
#define IF_NOLONG 0x00000800UL /* it's not available in long mode */
#define IF_UNDOC 0x00001000UL /* it's an undocumented instruction */
#define IF_FPU 0x00002000UL /* it's an FPU instruction */