Skip to content

Commit 2469b8b

Browse files
author
H. Peter Anvin
committed
Add {rex} prefix, simplify prefix handling, better error messages
Add a {rex} prefix to force REX encoding (typically a redundant 40h prefix). For prefix parsing, we can use t_inttwo to encode the prefix slot number. Give more verbose error messages for encoding mismatches.
1 parent 5368e45 commit 2469b8b

File tree

12 files changed

+204
-121
lines changed

12 files changed

+204
-121
lines changed

asm/assemble.c

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -935,15 +935,13 @@ int64_t assemble(int32_t segment, int64_t start, int bits, insn *instruction)
935935
nasm_nonfatal("instruction not supported in %d-bit mode", bits);
936936
break;
937937
case MERR_ENCMISMATCH:
938-
nasm_nonfatal("specific encoding scheme not available");
938+
nasm_nonfatal("instruction not encodable with %s prefix",
939+
prefix_name(instruction->prefixes[PPS_REX]));
939940
break;
940941
case MERR_BADBND:
941-
nasm_nonfatal("bnd prefix is not allowed");
942-
break;
943942
case MERR_BADREPNE:
944943
nasm_nonfatal("%s prefix is not allowed",
945-
(has_prefix(instruction, PPS_REP, P_REPNE) ?
946-
"repne" : "repnz"));
944+
prefix_name(instruction->prefixes[PPS_REP]));
947945
break;
948946
case MERR_REGSETSIZE:
949947
nasm_nonfatal("invalid register set size");
@@ -1644,16 +1642,22 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits,
16441642
ins->rex &= ~REX_P; /* Don't force REX prefix due to high reg */
16451643
}
16461644

1647-
switch (ins->prefixes[PPS_VEX]) {
1645+
switch (ins->prefixes[PPS_REX]) {
16481646
case P_EVEX:
16491647
if (!(ins->rex & REX_EV))
16501648
return -1;
16511649
break;
1650+
case P_VEX:
16521651
case P_VEX3:
16531652
case P_VEX2:
16541653
if (!(ins->rex & REX_V))
16551654
return -1;
16561655
break;
1656+
case P_REX:
1657+
if (ins->rex & (REX_V|REX_EV))
1658+
return -1;
1659+
ins->rex |= REX_P; /* Force REX prefix */
1660+
break;
16571661
default:
16581662
break;
16591663
}
@@ -1687,16 +1691,19 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits,
16871691
nasm_nonfatal("invalid high-16 register in non-AVX-512");
16881692
return -1;
16891693
}
1690-
if (ins->rex & REX_EV)
1694+
if (ins->rex & REX_EV) {
16911695
length += 4;
1692-
else if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B)) ||
1693-
ins->prefixes[PPS_VEX] == P_VEX3)
1696+
} else if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B)) ||
1697+
ins->prefixes[PPS_REX] == P_VEX3) {
1698+
if (ins->prefixes[PPS_REX] == P_VEX2)
1699+
nasm_nonfatal("instruction not encodable with {vex2} prefix");
16941700
length += 3;
1695-
else
1701+
} else {
16961702
length += 2;
1703+
}
16971704
} else if (ins->rex & REX_MASK) {
16981705
if (ins->rex & REX_H) {
1699-
nasm_nonfatal("cannot use high register in rex instruction");
1706+
nasm_nonfatal("cannot use high byte register in rex instruction");
17001707
return -1;
17011708
} else if (bits == 64) {
17021709
length++;
@@ -1849,6 +1856,8 @@ static int emit_prefix(struct out_data *data, const int bits, insn *ins)
18491856
case P_OSP:
18501857
c = 0x66;
18511858
break;
1859+
case P_REX:
1860+
case P_VEX:
18521861
case P_EVEX:
18531862
case P_VEX3:
18541863
case P_VEX2:
@@ -1994,7 +2003,7 @@ static void gencode(struct out_data *data, insn *ins)
19942003

19952004
case 0172:
19962005
{
1997-
int mask = ins->prefixes[PPS_VEX] == P_EVEX ? 7 : 15;
2006+
int mask = ins->prefixes[PPS_REX] == P_EVEX ? 7 : 15;
19982007
const struct operand *opy;
19992008

20002009
c = *codes++;
@@ -2054,7 +2063,7 @@ static void gencode(struct out_data *data, insn *ins)
20542063
case 0270:
20552064
codes += 2;
20562065
if (ins->vex_cm != 1 || (ins->rex & (REX_W|REX_X|REX_B)) ||
2057-
ins->prefixes[PPS_VEX] == P_VEX3) {
2066+
ins->prefixes[PPS_REX] == P_VEX3) {
20582067
bytes[0] = (ins->vex_cm >> 6) ? 0x8f : 0xc4;
20592068
bytes[1] = (ins->vex_cm & 31) | ((~ins->rex & 7) << 5);
20602069
bytes[2] = ((ins->rex & REX_W) << (7-3)) |
@@ -2383,11 +2392,12 @@ static enum match_result find_match(const struct itemplate **tempp,
23832392
int i;
23842393

23852394
/* broadcasting uses a different data element size */
2386-
for (i = 0; i < instruction->operands; i++)
2395+
for (i = 0; i < instruction->operands; i++) {
23872396
if (i == broadcast)
23882397
xsizeflags[i] = instruction->oprs[i].decoflags & BRSIZE_MASK;
23892398
else
23902399
xsizeflags[i] = instruction->oprs[i].type & SIZE_MASK;
2400+
}
23912401

23922402
merr = MERR_INVALOP;
23932403

@@ -2507,18 +2517,24 @@ static enum match_result matches(const struct itemplate *itemp,
25072517
return MERR_INVALOP;
25082518

25092519
/*
2510-
* {evex} available?
2520+
* {rex/vexn/evex} available?
25112521
*/
2512-
switch (instruction->prefixes[PPS_VEX]) {
2522+
switch (instruction->prefixes[PPS_REX]) {
25132523
case P_EVEX:
25142524
if (!itemp_has(itemp, IF_EVEX))
25152525
return MERR_ENCMISMATCH;
25162526
break;
2527+
case P_VEX:
25172528
case P_VEX3:
25182529
case P_VEX2:
25192530
if (!itemp_has(itemp, IF_VEX))
25202531
return MERR_ENCMISMATCH;
25212532
break;
2533+
case P_REX:
2534+
if (itemp_has(itemp, IF_VEX) || itemp_has(itemp, IF_EVEX) ||
2535+
bits != 64)
2536+
return MERR_ENCMISMATCH;
2537+
break;
25222538
default:
25232539
break;
25242540
}
@@ -2667,6 +2683,9 @@ static enum match_result matches(const struct itemplate *itemp,
26672683
* considered a wildcard match rather than an error.
26682684
*/
26692685
opsizemissing = true;
2686+
} else if (is_class(REG_HIGH, type) &&
2687+
instruction->prefixes[PPS_REX]) {
2688+
return MERR_ENCMISMATCH;
26702689
}
26712690
} else if (is_broadcast &&
26722691
(brcast_num !=
@@ -2764,13 +2783,14 @@ static enum match_result matches(const struct itemplate *itemp,
27642783

27652784
static enum ea_type process_ea(operand *input, ea *output, int bits,
27662785
int rfield, opflags_t rflags, insn *ins,
2767-
const char **errmsg)
2786+
const char **errmsgp)
27682787
{
27692788
bool forw_ref = !!(input->opflags & OPFLAG_UNKNOWN);
27702789
int addrbits = ins->addr_size;
27712790
int eaflags = input->eaflags;
2791+
const char *errmsg = NULL;
27722792

2773-
*errmsg = "invalid effective address"; /* Default error message */
2793+
errmsg = NULL;
27742794

27752795
output->type = EA_SCALAR;
27762796
output->rip = false;
@@ -2793,7 +2813,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
27932813

27942814
/* broadcasting is not available with a direct register operand. */
27952815
if (input->decoflags & BRDCAST_MASK) {
2796-
*errmsg = "broadcast not allowed with register operand";
2816+
errmsg = "broadcast not allowed with register operand";
27972817
goto err;
27982818
}
27992819

@@ -2809,7 +2829,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
28092829

28102830
/* Embedded rounding or SAE is not available with a mem ref operand. */
28112831
if (input->decoflags & (ER | SAE)) {
2812-
*errmsg = "embedded rounding is available only with "
2832+
errmsg = "embedded rounding is available only with "
28132833
"register-register operations";
28142834
goto err;
28152835
}
@@ -2838,7 +2858,7 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
28382858
}
28392859

28402860
if (bits == 64 && !(IP_REL & ~input->type) && (eaflags & EAF_SIB)) {
2841-
*errmsg = "instruction requires SIB encoding, cannot be RIP-relative";
2861+
errmsg = "instruction requires SIB encoding, cannot be RIP-relative";
28422862
goto err;
28432863
}
28442864

@@ -3224,6 +3244,14 @@ static enum ea_type process_ea(operand *input, ea *output, int bits,
32243244
return output->type;
32253245

32263246
err:
3247+
if (!errmsg) {
3248+
/* Default error message */
3249+
static char invalid_address_msg[40];
3250+
snprintf(invalid_address_msg, sizeof invalid_address_msg,
3251+
"invalid %d-bit effective address", bits);
3252+
errmsg = invalid_address_msg;
3253+
}
3254+
*errmsgp = errmsg;
32273255
return output->type = EA_INVALID;
32283256
}
32293257

asm/parser.c

Lines changed: 40 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -55,50 +55,6 @@ static int end_expression_next(void);
5555

5656
static struct tokenval tokval;
5757

58-
static int prefix_slot(int prefix)
59-
{
60-
switch (prefix) {
61-
case P_WAIT:
62-
return PPS_WAIT;
63-
case R_CS:
64-
case R_DS:
65-
case R_SS:
66-
case R_ES:
67-
case R_FS:
68-
case R_GS:
69-
return PPS_SEG;
70-
case P_LOCK:
71-
return PPS_LOCK;
72-
case P_REP:
73-
case P_REPE:
74-
case P_REPZ:
75-
case P_REPNE:
76-
case P_REPNZ:
77-
case P_XACQUIRE:
78-
case P_XRELEASE:
79-
case P_BND:
80-
case P_NOBND:
81-
return PPS_REP;
82-
case P_O16:
83-
case P_O32:
84-
case P_O64:
85-
case P_OSP:
86-
return PPS_OSIZE;
87-
case P_A16:
88-
case P_A32:
89-
case P_A64:
90-
case P_ASP:
91-
return PPS_ASIZE;
92-
case P_EVEX:
93-
case P_VEX3:
94-
case P_VEX2:
95-
return PPS_VEX;
96-
default:
97-
nasm_panic("Invalid value %d passed to prefix_slot()", prefix);
98-
return -1;
99-
}
100-
}
101-
10258
static void process_size_override(insn *result, operand *op)
10359
{
10460
if (tasm_compatible_mode) {
@@ -185,7 +141,7 @@ static void process_size_override(insn *result, operand *op)
185141
}
186142

187143
/*
188-
* Brace decorators are are parsed here. opmask and zeroing
144+
* Braced keywords are are parsed here. opmask and zeroing
189145
* decorators can be placed in any order. e.g. zmm1 {k2}{z} or zmm2
190146
* {z}{k3} decorator(s) are placed at the end of an operand.
191147
*/
@@ -715,42 +671,51 @@ insn *parse_line(char *buffer, insn *result)
715671
if (i == TOKEN_EOS)
716672
goto fail;
717673

718-
while (i == TOKEN_PREFIX ||
719-
(i == TOKEN_REG && IS_SREG(tokval.t_integer))) {
720-
first = false;
674+
while (i) {
675+
int slot = PPS_SEG;
721676

722-
/*
723-
* Handle special case: the TIMES prefix.
724-
*/
725-
if (i == TOKEN_PREFIX && tokval.t_integer == P_TIMES) {
726-
expr *value;
677+
if (i == TOKEN_PREFIX) {
678+
slot = tokval.t_inttwo;
727679

728-
i = stdscan(NULL, &tokval);
729-
value = evaluate(stdscan, NULL, &tokval, NULL, pass_stable(), NULL);
730-
i = tokval.t_type;
731-
if (!value) /* Error in evaluator */
732-
goto fail;
733-
if (!is_simple(value)) {
734-
nasm_nonfatal("non-constant argument supplied to TIMES");
735-
result->times = 1L;
736-
} else {
737-
result->times = value->value;
738-
if (value->value < 0) {
739-
nasm_nonfatalf(ERR_PASS2, "TIMES value %"PRId64" is negative", value->value);
740-
result->times = 0;
680+
if (slot == PPS_TIMES) {
681+
/* TIMES is a very special prefix */
682+
expr *value;
683+
684+
i = stdscan(NULL, &tokval);
685+
value = evaluate(stdscan, NULL, &tokval, NULL,
686+
pass_stable(), NULL);
687+
i = tokval.t_type;
688+
if (!value) /* Error in evaluator */
689+
goto fail;
690+
if (!is_simple(value)) {
691+
nasm_nonfatal("non-constant argument supplied to TIMES");
692+
result->times = 1;
693+
} else {
694+
result->times = value->value;
695+
if (value->value < 0) {
696+
nasm_nonfatalf(ERR_PASS2, "TIMES value %"PRId64" is negative", value->value);
697+
result->times = 0;
698+
}
741699
}
700+
first = false;
701+
continue;
742702
}
703+
} else if (i == TOKEN_REG && IS_SREG(tokval.t_integer)) {
704+
slot = PPS_SEG;
705+
first = false;
743706
} else {
744-
int slot = prefix_slot(tokval.t_integer);
745-
if (result->prefixes[slot]) {
746-
if (result->prefixes[slot] == tokval.t_integer)
747-
nasm_warn(WARN_OTHER, "instruction has redundant prefixes");
748-
else
749-
nasm_nonfatal("instruction has conflicting prefixes");
750-
}
751-
result->prefixes[slot] = tokval.t_integer;
752-
i = stdscan(NULL, &tokval);
707+
break; /* Not a prefix */
753708
}
709+
710+
if (result->prefixes[slot]) {
711+
if (result->prefixes[slot] == tokval.t_integer)
712+
nasm_warn(WARN_OTHER, "instruction has redundant prefixes");
713+
else
714+
nasm_nonfatal("instruction has conflicting prefixes");
715+
}
716+
result->prefixes[slot] = tokval.t_integer;
717+
i = stdscan(NULL, &tokval);
718+
first = false;
754719
}
755720

756721
if (i != TOKEN_INSN) {

0 commit comments

Comments
 (0)