diff options
author | H. Peter Anvin <hpa@zytor.com> | 2009-07-25 18:15:28 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-07-25 18:15:28 -0700 |
commit | a81655bffb3841a0326c7224403f8c8e7cccd82a (patch) | |
tree | 0d3f2da0698d2c8967b755c47416e0f6f2c9e4dc /assemble.c | |
parent | 23595f5946bc816185204302a78d8413ed59cc4b (diff) | |
download | nasm-a81655bffb3841a0326c7224403f8c8e7cccd82a.tar.gz nasm-a81655bffb3841a0326c7224403f8c8e7cccd82a.tar.bz2 nasm-a81655bffb3841a0326c7224403f8c8e7cccd82a.zip |
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.c | 49 |
1 files changed, 46 insertions, 3 deletions
@@ -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; |