0
0
mirror of https://github.com/netwide-assembler/nasm.git synced 2025-11-08 23:27:15 -05:00

Fix matching of branch instructions with prefixes and sizes

Matching of branch instructions with prefixes and sizes is, to say the
least, tricky. Work through it, and add a new macro to help.

Fixes: https://github.com/netwide-assembler/nasm/issues/144
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin (Intel)
2025-10-10 13:03:33 -07:00
parent 2c71e67762
commit a7457e66cf
22 changed files with 6875 additions and 100 deletions

View File

@@ -1400,28 +1400,9 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
ins->itemp = temp; /* Instruction template */
eat = EA_SCALAR; /* Expect a scalar EA */
/* Default operand size */
/* Default operand size (prefixes are handled in the byte code) */
ins->op_size = bits != 16 ? 32 : 16;
if (bits == 64) {
if (ins->prefixes[PPS_ASIZE] == P_A16) {
nasm_warn(WARN_PREFIX_BADMODE_A16,
"a64 prefix invalid in 64-bit mode");
ins->prefixes[PPS_ASIZE] = 0;
}
} else {
if (ins->prefixes[PPS_OSIZE] == P_O64) {
nasm_warn(WARN_PREFIX_BADMODE_O64,
"o64 prefix invalid in %d-bit mode", bits);
ins->prefixes[PPS_OSIZE] = P_none;
}
if (ins->prefixes[PPS_ASIZE] == P_A64) {
nasm_warn(WARN_PREFIX_BADMODE_A64,
"a64 prefix invalid in %d-bit mode", bits);
ins->prefixes[PPS_ASIZE] = P_none;
}
}
nasm_zero(need_pfx);
while (*codes) {
@@ -3061,7 +3042,7 @@ static enum match_result matches(const struct itemplate * const itemp,
/* "Default" operand size (from mode and prefixes only) */
op_size = ins->op_size;
if (itemp_has(itemp, IF_NWSIZE) && op_size == 32) {
if (bits == 64 && itemp_has(itemp, IF_NWSIZE) && op_size == 32) {
/* If this is an nw instruction, default to 64 bits in 64-bit mode */
op_size = bits;
}
@@ -3101,18 +3082,23 @@ static enum match_result matches(const struct itemplate * const itemp,
/* Handle implied SHORT or NEAR */
if (unlikely(ttype & (NEAR|SHORT))) {
/* Treat BYTE as an alias for SHORT, ignoring size */
if (isize[i] == BITS8) {
itype[i] |= SHORT;
isize[i] = 0;
}
/* An explicit SHORT or BITS8 cancels NEAR; are synonyms */
if (itype[i] & SHORT) {
itype[i] &= ~NEAR;
}
/* NEAR is implicit unless otherwise specified */
if (!(itype[i] & (FAR|SHORT))) {
itype[i] |= ttype & NEAR;
}
if ((ttype & (NEAR|SHORT)) == (NEAR|SHORT)) {
/* Only a short form exists; allow both NEAR and SHORT */
/* Only a short form exists; this is specially coded */
if (!(itype[i] & (FAR|ABS)))
itype[i] |= NEAR|SHORT;
} else if ((itype[i] & SHORT) || isize[i] == BITS8) {
/* An explicit SHORT or BITS8 cancel NEAR; are synonyms */
itype[i] &= ~NEAR;
if (!isize[i])
isize[i] = BITS8;
} else if (!(itype[i] & (FAR|ABS|SHORT))) {
/* NEAR is implicit unless otherwise specified */
itype[i] |= ttype & NEAR;
}
}

View File

@@ -964,8 +964,10 @@ restart_parse:
while (i == TOKEN_SPECIAL || i == TOKEN_SIZE) {
switch (tokval.t_integer) {
case S_BYTE:
if (!setsize) /* we want to use only the first */
if (!setsize) { /* we want to use only the first */
result->opt |= OPTIM_NO_Jcc_RELAX | OPTIM_NO_JMP_RELAX;
op->type |= BITS8;
}
setsize = 1;
break;
case S_WORD:
@@ -1014,9 +1016,12 @@ restart_parse:
op->type |= FAR;
break;
case S_NEAR:
/* This is not legacy behavior, even if it perhaps should be */
/* result->opt |= OPTIM_NO_Jcc_RELAX | OPTIM_NO_JMP_RELAX; */
op->type |= NEAR;
break;
case S_SHORT:
result->opt |= OPTIM_NO_Jcc_RELAX | OPTIM_NO_JMP_RELAX;
op->type |= SHORT;
break;
case S_ABS:

View File

@@ -259,20 +259,11 @@ pragma-unknown [off] unknown \c{%pragma} facility or directive
Warns about an unknown \c{%pragma} directive.
This is not yet implemented for most cases.
prefix-badmode-a64 [err] a64 prefix invalid in 16/32-bit mode
Warns that an \c{a64} prefix was specified in 16- or 32-bit
mode. If the error is demoted to a warning or suppressed, the
prefix is ignored by the assembler.
prefix-badmode-o64 [err] o64 prefix invalid in 16/32-bit mode
Warns that an \c{a64} prefix was specified in 16- or 32-bit
mode. If the error is demoted to a warning or suppressed, the
prefix is ignored by the assembler.
prefix-badmode-a16 [err] a16 prefix invalid in 64-bit mode
Warns that an \c{a16} prefix was specified in 64-bit mode.
If the error is demoted to a warning or suppressed, the
prefix is ignored by the assembler.
prefix is ignored by the assembler, but is likely to trigger
futher errors.
prefix-bnd [on] invalid \c{BND} prefix
=bnd