mirror of
https://github.com/netwide-assembler/nasm.git
synced 2024-11-21 03:14:19 +08:00
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>
This commit is contained in:
parent
23595f5946
commit
a81655bffb
49
assemble.c
49
assemble.c
@ -1983,9 +1983,52 @@ 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;
|
||||
|
||||
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;
|
||||
} 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)
|
||||
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);
|
||||
@ -1998,9 +2041,10 @@ static enum match_result find_match(const struct itemplate **tempp,
|
||||
if (m > merr)
|
||||
merr = m;
|
||||
if (merr == MOK_GOOD)
|
||||
break;
|
||||
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;
|
||||
|
25
insns.h
25
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 */
|
||||
|
Loading…
Reference in New Issue
Block a user