From a81655bffb3841a0326c7224403f8c8e7cccd82a Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Sat, 25 Jul 2009 18:15:28 -0700 Subject: 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 --- assemble.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) (limited to 'assemble.c') 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; -- cgit v1.2.1