aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2022-12-12 13:51:46 +0100
committerJan Beulich <jbeulich@suse.com>2022-12-12 13:51:46 +0100
commit04784e33fabb45c4de7a901587f468d4bc169649 (patch)
tree1078958623209c3e73645c9f3721e825b012b6a5 /gas
parent5317ad2ccc3d0099551140a20c1b12fe22030736 (diff)
downloadgdb-04784e33fabb45c4de7a901587f468d4bc169649.zip
gdb-04784e33fabb45c4de7a901587f468d4bc169649.tar.gz
gdb-04784e33fabb45c4de7a901587f468d4bc169649.tar.bz2
x86: re-work insn/suffix recognition
Having templates with a suffix explicitly present has always been quirky. Introduce a 2nd matching pass in case the 1st one couldn't find a suitable template _and_ didn't itself already need to trim off a suffix to find a match at all. This requires error reporting adjustments (albeit luckily fewer than I was afraid might be necessary), as errors previously reported during matching now need deferring until after the 2nd pass (because, obviously, we must not emit any error if the 2nd pass succeeds). While also related to PR gas/29524, it was requested that move-with-sign-extend be left as broken as it always was. PR gas/29525 Note that with the dropped CMPSD and MOVSD Intel Syntax string insn templates taking operands, mixed IsString/non-IsString template groups (with memory operands) cannot occur anymore. With that maybe_adjust_templates() becomes unnecessary (and is hence being removed). PR gas/29526 Note further that while the additions to the intel16 testcase aren't really proper Intel syntax, we've been permitting all of those except for the MOVD variant. The test therefore is to avoid re-introducing such an inconsistency.
Diffstat (limited to 'gas')
-rw-r--r--gas/config/tc-i386-intel.c11
-rw-r--r--gas/config/tc-i386.c317
-rw-r--r--gas/testsuite/gas/i386/code16.d1
-rw-r--r--gas/testsuite/gas/i386/code16.e3
-rw-r--r--gas/testsuite/gas/i386/code16.s4
-rw-r--r--gas/testsuite/gas/i386/intel16.d10
-rw-r--r--gas/testsuite/gas/i386/intel16.s12
7 files changed, 195 insertions, 163 deletions
diff --git a/gas/config/tc-i386-intel.c b/gas/config/tc-i386-intel.c
index 54b124b..ca18f5e 100644
--- a/gas/config/tc-i386-intel.c
+++ b/gas/config/tc-i386-intel.c
@@ -1000,10 +1000,7 @@ i386_intel_operand (char *operand_string, int got_a_float)
|| intel_state.is_mem)
{
/* Memory operand. */
- if (i.mem_operands == 1 && !maybe_adjust_templates ())
- return 0;
- if ((int) i.mem_operands
- >= 2 - !current_templates->start->opcode_modifier.isstring)
+ if (i.mem_operands)
{
/* Handle
@@ -1048,10 +1045,6 @@ i386_intel_operand (char *operand_string, int got_a_float)
}
}
}
-
- as_bad (_("too many memory references for `%s'"),
- current_templates->start->name);
- return 0;
}
/* Swap base and index in 16-bit memory operands like
@@ -1165,8 +1158,6 @@ i386_intel_operand (char *operand_string, int got_a_float)
return 0;
i.flags[this_operand] |= Operand_Mem;
- if (i.mem_operands == 0)
- i.memop1_string = xstrdup (operand_string);
++i.mem_operands;
}
else
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index e4c4198..870e2d1 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -298,9 +298,6 @@ struct _i386_insn
explicit segment overrides are given. */
const reg_entry *seg[2];
- /* Copied first memory operand string, for re-checking. */
- char *memop1_string;
-
/* PREFIX holds all the given prefix opcodes (usually null).
PREFIXES is the number of prefix opcodes. */
unsigned int prefixes;
@@ -4299,7 +4296,20 @@ optimize_encoding (void)
movq $imm31, %r64 -> movl $imm31, %r32
movq $imm32, %r64 -> movl $imm32, %r32
*/
- i.tm.opcode_modifier.norex64 = 1;
+ i.tm.opcode_modifier.size = SIZE32;
+ if (i.imm_operands)
+ {
+ i.types[0].bitfield.imm32 = 1;
+ i.types[0].bitfield.imm32s = 0;
+ i.types[0].bitfield.imm64 = 0;
+ }
+ else
+ {
+ i.types[0].bitfield.dword = 1;
+ i.types[0].bitfield.qword = 0;
+ }
+ i.types[1].bitfield.dword = 1;
+ i.types[1].bitfield.qword = 0;
if (i.tm.base_opcode == 0xb8 || (i.tm.base_opcode | 1) == 0xc7)
{
/* Handle
@@ -4309,11 +4319,6 @@ optimize_encoding (void)
i.tm.operand_types[0].bitfield.imm32 = 1;
i.tm.operand_types[0].bitfield.imm32s = 0;
i.tm.operand_types[0].bitfield.imm64 = 0;
- i.types[0].bitfield.imm32 = 1;
- i.types[0].bitfield.imm32s = 0;
- i.types[0].bitfield.imm64 = 0;
- i.types[1].bitfield.dword = 1;
- i.types[1].bitfield.qword = 0;
if ((i.tm.base_opcode | 1) == 0xc7)
{
/* Handle
@@ -4836,6 +4841,18 @@ insert_lfence_before (void)
}
}
+/* Helper for md_assemble() to decide whether to prepare for a possible 2nd
+ parsing pass. Instead of introducing a rarely use new insn attribute this
+ utilizes a common pattern between affected templates. It is deemed
+ acceptable that this will lead to unnecessary pass 2 preparations in a
+ limited set of cases. */
+static INLINE bool may_need_pass2 (const insn_template *t)
+{
+ return t->opcode_modifier.sse2avx
+ /* Note that all SSE2AVX templates have at least one operand. */
+ && t->operand_types[t->operands - 1].bitfield.class == RegSIMD;
+}
+
/* This is the guts of the machine-dependent assembler. LINE points to a
machine dependent instruction. This function is supposed to emit
the frags/bytes it assembles to. */
@@ -4844,11 +4861,14 @@ void
md_assemble (char *line)
{
unsigned int j;
- char mnemonic[MAX_MNEM_SIZE], mnem_suffix;
- const char *end;
+ char mnemonic[MAX_MNEM_SIZE], mnem_suffix, *copy = NULL;
+ const char *end, *pass1_mnem = NULL;
+ enum i386_error pass1_err = 0;
const insn_template *t;
/* Initialize globals. */
+ current_templates = NULL;
+ retry:
memset (&i, '\0', sizeof (i));
i.rounding.type = rc_none;
for (j = 0; j < MAX_OPERANDS; j++)
@@ -4863,16 +4883,26 @@ md_assemble (char *line)
end = parse_insn (line, mnemonic);
if (end == NULL)
- return;
+ {
+ if (pass1_mnem != NULL)
+ goto match_error;
+ return;
+ }
+ if (may_need_pass2 (current_templates->start))
+ {
+ /* Make a copy of the full line in case we need to retry. */
+ copy = xstrdup (line);
+ }
line += end - line;
mnem_suffix = i.suffix;
line = parse_operands (line, mnemonic);
this_operand = -1;
- xfree (i.memop1_string);
- i.memop1_string = NULL;
if (line == NULL)
- return;
+ {
+ free (copy);
+ return;
+ }
/* Now we've parsed the mnemonic into a set of templates, and have the
operands at hand. */
@@ -4950,7 +4980,97 @@ md_assemble (char *line)
with the template operand types. */
if (!(t = match_template (mnem_suffix)))
- return;
+ {
+ const char *err_msg;
+
+ if (copy && !mnem_suffix)
+ {
+ line = copy;
+ copy = NULL;
+ pass1_err = i.error;
+ pass1_mnem = current_templates->start->name;
+ goto retry;
+ }
+ free (copy);
+ match_error:
+ switch (pass1_mnem ? pass1_err : i.error)
+ {
+ default:
+ abort ();
+ case operand_size_mismatch:
+ err_msg = _("operand size mismatch");
+ break;
+ case operand_type_mismatch:
+ err_msg = _("operand type mismatch");
+ break;
+ case register_type_mismatch:
+ err_msg = _("register type mismatch");
+ break;
+ case number_of_operands_mismatch:
+ err_msg = _("number of operands mismatch");
+ break;
+ case invalid_instruction_suffix:
+ err_msg = _("invalid instruction suffix");
+ break;
+ case bad_imm4:
+ err_msg = _("constant doesn't fit in 4 bits");
+ break;
+ case unsupported_with_intel_mnemonic:
+ err_msg = _("unsupported with Intel mnemonic");
+ break;
+ case unsupported_syntax:
+ err_msg = _("unsupported syntax");
+ break;
+ case unsupported:
+ as_bad (_("unsupported instruction `%s'"),
+ pass1_mnem ? pass1_mnem : current_templates->start->name);
+ return;
+ case invalid_sib_address:
+ err_msg = _("invalid SIB address");
+ break;
+ case invalid_vsib_address:
+ err_msg = _("invalid VSIB address");
+ break;
+ case invalid_vector_register_set:
+ err_msg = _("mask, index, and destination registers must be distinct");
+ break;
+ case invalid_tmm_register_set:
+ err_msg = _("all tmm registers must be distinct");
+ break;
+ case invalid_dest_and_src_register_set:
+ err_msg = _("destination and source registers must be distinct");
+ break;
+ case unsupported_vector_index_register:
+ err_msg = _("unsupported vector index register");
+ break;
+ case unsupported_broadcast:
+ err_msg = _("unsupported broadcast");
+ break;
+ case broadcast_needed:
+ err_msg = _("broadcast is needed for operand of such type");
+ break;
+ case unsupported_masking:
+ err_msg = _("unsupported masking");
+ break;
+ case mask_not_on_destination:
+ err_msg = _("mask not on destination operand");
+ break;
+ case no_default_mask:
+ err_msg = _("default mask isn't allowed");
+ break;
+ case unsupported_rc_sae:
+ err_msg = _("unsupported static rounding/sae");
+ break;
+ case invalid_register_operand:
+ err_msg = _("invalid register operand");
+ break;
+ }
+ as_bad (_("%s for `%s'"), err_msg,
+ pass1_mnem ? pass1_mnem : current_templates->start->name);
+ return;
+ }
+
+ free (copy);
if (sse_check != check_none
/* The opcode space check isn't strictly needed; it's there only to
@@ -5267,6 +5387,7 @@ parse_insn (const char *line, char *mnemonic)
{
const char *l = line, *token_start = l;
char *mnem_p;
+ bool pass1 = !current_templates;
int supported;
const insn_template *t;
char *dot_p = NULL;
@@ -5436,8 +5557,10 @@ parse_insn (const char *line, char *mnemonic)
current_templates = (const templates *) str_hash_find (op_hash, mnemonic);
}
- if (!current_templates)
+ if (!current_templates || !pass1)
{
+ current_templates = NULL;
+
check_suffix:
if (mnem_p > mnemonic)
{
@@ -5479,13 +5602,39 @@ parse_insn (const char *line, char *mnemonic)
current_templates
= (const templates *) str_hash_find (op_hash, mnemonic);
}
+ /* For compatibility reasons accept MOVSD and CMPSD without
+ operands even in AT&T mode. */
+ else if (*l == END_OF_INSN
+ || (is_space_char (*l) && l[1] == END_OF_INSN))
+ {
+ mnem_p[-1] = '\0';
+ current_templates
+ = (const templates *) str_hash_find (op_hash, mnemonic);
+ if (current_templates != NULL
+ /* MOVS or CMPS */
+ && (current_templates->start->base_opcode | 2) == 0xa6
+ && current_templates->start->opcode_modifier.opcodespace
+ == SPACE_BASE
+ && mnem_p[-2] == 's')
+ {
+ as_warn (_("found `%sd'; assuming `%sl' was meant"),
+ mnemonic, mnemonic);
+ i.suffix = LONG_MNEM_SUFFIX;
+ }
+ else
+ {
+ current_templates = NULL;
+ mnem_p[-1] = 'd';
+ }
+ }
break;
}
}
if (!current_templates)
{
- as_bad (_("no such instruction: `%s'"), token_start);
+ if (pass1)
+ as_bad (_("no such instruction: `%s'"), token_start);
return NULL;
}
}
@@ -6873,81 +7022,7 @@ match_template (char mnem_suffix)
if (t == current_templates->end)
{
/* We found no match. */
- const char *err_msg;
- switch (specific_error)
- {
- default:
- abort ();
- case operand_size_mismatch:
- err_msg = _("operand size mismatch");
- break;
- case operand_type_mismatch:
- err_msg = _("operand type mismatch");
- break;
- case register_type_mismatch:
- err_msg = _("register type mismatch");
- break;
- case number_of_operands_mismatch:
- err_msg = _("number of operands mismatch");
- break;
- case invalid_instruction_suffix:
- err_msg = _("invalid instruction suffix");
- break;
- case bad_imm4:
- err_msg = _("constant doesn't fit in 4 bits");
- break;
- case unsupported_with_intel_mnemonic:
- err_msg = _("unsupported with Intel mnemonic");
- break;
- case unsupported_syntax:
- err_msg = _("unsupported syntax");
- break;
- case unsupported:
- as_bad (_("unsupported instruction `%s'"),
- current_templates->start->name);
- return NULL;
- case invalid_sib_address:
- err_msg = _("invalid SIB address");
- break;
- case invalid_vsib_address:
- err_msg = _("invalid VSIB address");
- break;
- case invalid_vector_register_set:
- err_msg = _("mask, index, and destination registers must be distinct");
- break;
- case invalid_tmm_register_set:
- err_msg = _("all tmm registers must be distinct");
- break;
- case invalid_dest_and_src_register_set:
- err_msg = _("destination and source registers must be distinct");
- break;
- case unsupported_vector_index_register:
- err_msg = _("unsupported vector index register");
- break;
- case unsupported_broadcast:
- err_msg = _("unsupported broadcast");
- break;
- case broadcast_needed:
- err_msg = _("broadcast is needed for operand of such type");
- break;
- case unsupported_masking:
- err_msg = _("unsupported masking");
- break;
- case mask_not_on_destination:
- err_msg = _("mask not on destination operand");
- break;
- case no_default_mask:
- err_msg = _("default mask isn't allowed");
- break;
- case unsupported_rc_sae:
- err_msg = _("unsupported static rounding/sae");
- break;
- case invalid_register_operand:
- err_msg = _("invalid register operand");
- break;
- }
- as_bad (_("%s for `%s'"), err_msg,
- current_templates->start->name);
+ i.error = specific_error;
return NULL;
}
@@ -11426,49 +11501,6 @@ RC_SAE_immediate (const char *imm_start)
return 1;
}
-/* Only string instructions can have a second memory operand, so
- reduce current_templates to just those if it contains any. */
-static int
-maybe_adjust_templates (void)
-{
- const insn_template *t;
-
- gas_assert (i.mem_operands == 1);
-
- for (t = current_templates->start; t < current_templates->end; ++t)
- if (t->opcode_modifier.isstring)
- break;
-
- if (t < current_templates->end)
- {
- static templates aux_templates;
- bool recheck;
-
- aux_templates.start = t;
- for (; t < current_templates->end; ++t)
- if (!t->opcode_modifier.isstring)
- break;
- aux_templates.end = t;
-
- /* Determine whether to re-check the first memory operand. */
- recheck = (aux_templates.start != current_templates->start
- || t != current_templates->end);
-
- current_templates = &aux_templates;
-
- if (recheck)
- {
- i.mem_operands = 0;
- if (i.memop1_string != NULL
- && i386_index_check (i.memop1_string) == 0)
- return 0;
- i.mem_operands = 1;
- }
- }
-
- return 1;
-}
-
static INLINE bool starts_memory_operand (char c)
{
return ISDIGIT (c)
@@ -11619,17 +11651,6 @@ i386_att_operand (char *operand_string)
char *displacement_string_end;
do_memory_reference:
- if (i.mem_operands == 1 && !maybe_adjust_templates ())
- return 0;
- if ((i.mem_operands == 1
- && !current_templates->start->opcode_modifier.isstring)
- || i.mem_operands == 2)
- {
- as_bad (_("too many memory references for `%s'"),
- current_templates->start->name);
- return 0;
- }
-
/* Check for base index form. We detect the base index form by
looking for an ')' at the end of the operand, searching
for the '(' matching it, and finding a REGISTER_PREFIX or ','
@@ -11837,8 +11858,6 @@ i386_att_operand (char *operand_string)
if (i386_index_check (operand_string) == 0)
return 0;
i.flags[this_operand] |= Operand_Mem;
- if (i.mem_operands == 0)
- i.memop1_string = xstrdup (operand_string);
i.mem_operands++;
}
else
diff --git a/gas/testsuite/gas/i386/code16.d b/gas/testsuite/gas/i386/code16.d
index 246be48..1b5a6dd 100644
--- a/gas/testsuite/gas/i386/code16.d
+++ b/gas/testsuite/gas/i386/code16.d
@@ -1,5 +1,6 @@
#objdump: -drw -mi8086
#name: i386 with .code16
+#warning_output: code16.e
.*: +file format .*
diff --git a/gas/testsuite/gas/i386/code16.e b/gas/testsuite/gas/i386/code16.e
new file mode 100644
index 0000000..7c68875
--- /dev/null
+++ b/gas/testsuite/gas/i386/code16.e
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:3: Warning: .* `movsd'.*`movsl'.*
+.*:4: Warning: .* `cmpsd'.*`cmpsl'.*
diff --git a/gas/testsuite/gas/i386/code16.s b/gas/testsuite/gas/i386/code16.s
index 407bb45..c5774e8 100644
--- a/gas/testsuite/gas/i386/code16.s
+++ b/gas/testsuite/gas/i386/code16.s
@@ -2,8 +2,8 @@
.code16
rep; movsd
rep; cmpsd
- rep movsd %ds:(%si),%es:(%di)
- rep cmpsd %es:(%di),%ds:(%si)
+ rep movsl %ds:(%si),%es:(%di)
+ rep cmpsl %es:(%di),%ds:(%si)
mov %cr2, %ecx
mov %ecx, %cr2
diff --git a/gas/testsuite/gas/i386/intel16.d b/gas/testsuite/gas/i386/intel16.d
index 45bb203..4adc41f 100644
--- a/gas/testsuite/gas/i386/intel16.d
+++ b/gas/testsuite/gas/i386/intel16.d
@@ -20,4 +20,12 @@ Disassembly of section .text:
2c: 8d 02 [ ]*lea \(%bp,%si\),%ax
2e: 8d 01 [ ]*lea \(%bx,%di\),%ax
30: 8d 03 [ ]*lea \(%bp,%di\),%ax
- ...
+[ ]*[0-9a-f]+: 67 f7 13[ ]+notw[ ]+\(%ebx\)
+[ ]*[0-9a-f]+: 66 f7 17[ ]+notl[ ]+\(%bx\)
+[ ]*[0-9a-f]+: 67 0f 1f 03[ ]+nopw[ ]+\(%ebx\)
+[ ]*[0-9a-f]+: 66 0f 1f 07[ ]+nopl[ ]+\(%bx\)
+[ ]*[0-9a-f]+: 67 83 03 05[ ]+addw[ ]+\$0x5,\(%ebx\)
+[ ]*[0-9a-f]+: 66 83 07 05[ ]+addl[ ]+\$0x5,\(%bx\)
+[ ]*[0-9a-f]+: 67 c7 03 05 00[ ]+movw[ ]+\$0x5,\(%ebx\)
+[ ]*[0-9a-f]+: 66 c7 07 05 00 00 00[ ]+movl[ ]+\$0x5,\(%bx\)
+#pass
diff --git a/gas/testsuite/gas/i386/intel16.s b/gas/testsuite/gas/i386/intel16.s
index 14a9792..4314e8d 100644
--- a/gas/testsuite/gas/i386/intel16.s
+++ b/gas/testsuite/gas/i386/intel16.s
@@ -18,4 +18,14 @@
lea ax, [di][bx]
lea ax, [di][bp]
- .p2align 4,0
+ notw [ebx]
+ notd [bx]
+
+ nopw [ebx]
+ nopd [bx]
+
+ addw [ebx], 5
+ addd [bx], 5
+
+ movw [ebx], 5
+ movd [bx], 5