Enable fuzzy matching of operand sizes
authorH. Peter Anvin <hpa@zytor.com>
Sun, 26 Jul 2009 01:15:28 +0000 (18:15 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Sun, 26 Jul 2009 01:15:28 +0000 (18:15 -0700)
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>
assemble.c
insns.h

index e5df728..829cb1b 100644 (file)
@@ -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 e8096a7..4ae2499 100644 (file)
--- 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 */