summaryrefslogtreecommitdiff
path: root/assemble.c
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 /assemble.c
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>
Diffstat (limited to 'assemble.c')
-rw-r--r--assemble.c49
1 files changed, 46 insertions, 3 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;