222 lines
7.1 KiB
Diff
222 lines
7.1 KiB
Diff
From e4afe464b120e181747b1108a23e0da2d16abd99 Mon Sep 17 00:00:00 2001
|
|
From: Richard Sandiford <richard.sandiford@arm.com>
|
|
Date: Tue, 30 Nov 2021 17:50:24 +0000
|
|
Subject: [PATCH 09/10] aarch64: Check for register aliases before mnemonics
|
|
|
|
Reference: https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=2dd3146b4ffcb8528a6e093741ba31636afdf8ae
|
|
|
|
Previously we would not accept:
|
|
|
|
A .req B
|
|
|
|
if A happened to be the name of an instruction. Adding new
|
|
instructions could therefore invalidate existing register aliases.
|
|
|
|
I noticed this with a test that used "zero" as a register alias
|
|
for "xzr", where "zero" is now also the name of an SME instruction.
|
|
I don't have any evidence that "real" code is doing this, but it
|
|
seems at least plausible.
|
|
|
|
This patch switches things so that we check for register aliases
|
|
first. It might slow down parsing slightly, but the difference
|
|
is unlikely to be noticeable.
|
|
|
|
Things like:
|
|
|
|
b .req + 0
|
|
|
|
still work, since create_register_alias checks for " .req ",
|
|
and with the input scrubber, we'll only keep whitespace after
|
|
.req if it's followed by another name. If there's some valid
|
|
expression that I haven't thought about that is scrubbed to
|
|
" .req ", users could avoid the ambiguity by wrapping .req
|
|
in parentheses.
|
|
|
|
The new test for invalid aliases already passed. I just wanted
|
|
something to exercise the !dot condition.
|
|
|
|
I can't find a way of exercising the (existing) p == base condition,
|
|
but I'm not brave enough to say that it can never happen. If it does
|
|
happen, get_mnemonic_name would return an empty string.
|
|
|
|
gas/
|
|
* config/tc-aarch64.c (opcode_lookup): Move mnemonic extraction
|
|
code to...
|
|
(md_assemble): ...here. Check for register aliases first.
|
|
* testsuite/gas/aarch64/register_aliases.d,
|
|
testsuite/gas/aarch64/register_aliases.s: Test for a register
|
|
alias called "zero".
|
|
* testsuite/gas/aarch64/register_aliases_invalid.d,
|
|
testsuite/gas/aarch64/register_aliases_invalid.l,
|
|
testsuite/gas/aarch64/register_aliases_invalid.s: New test.
|
|
---
|
|
gas/config/tc-aarch64.c | 62 +++++++++----------
|
|
gas/testsuite/gas/aarch64/register_aliases.d | 1 +
|
|
gas/testsuite/gas/aarch64/register_aliases.s | 3 +-
|
|
.../gas/aarch64/register_aliases_invalid.d | 1 +
|
|
.../gas/aarch64/register_aliases_invalid.l | 3 +
|
|
.../gas/aarch64/register_aliases_invalid.s | 2 +
|
|
6 files changed, 38 insertions(+), 34 deletions(-)
|
|
create mode 100644 gas/testsuite/gas/aarch64/register_aliases_invalid.d
|
|
create mode 100644 gas/testsuite/gas/aarch64/register_aliases_invalid.l
|
|
create mode 100644 gas/testsuite/gas/aarch64/register_aliases_invalid.s
|
|
|
|
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
|
|
index ea58d9b0..c9677edc 100644
|
|
--- a/gas/config/tc-aarch64.c
|
|
+++ b/gas/config/tc-aarch64.c
|
|
@@ -5786,25 +5786,18 @@ lookup_mnemonic (const char *start, int len)
|
|
}
|
|
|
|
/* Subroutine of md_assemble, responsible for looking up the primary
|
|
- opcode from the mnemonic the user wrote. STR points to the
|
|
- beginning of the mnemonic. */
|
|
+ opcode from the mnemonic the user wrote. BASE points to the beginning
|
|
+ of the mnemonic, DOT points to the first '.' within the mnemonic
|
|
+ (if any) and END points to the end of the mnemonic. */
|
|
|
|
static templates *
|
|
-opcode_lookup (char **str)
|
|
+opcode_lookup (char *base, char *dot, char *end)
|
|
{
|
|
- char *end, *base, *dot;
|
|
const aarch64_cond *cond;
|
|
char condname[16];
|
|
int len;
|
|
|
|
- /* Scan up to the end of the mnemonic, which must end in white space,
|
|
- '.', or end of string. */
|
|
- dot = 0;
|
|
- for (base = end = *str; is_part_of_name(*end); end++)
|
|
- if (*end == '.' && !dot)
|
|
- dot = end;
|
|
-
|
|
- if (end == base || dot == base)
|
|
+ if (dot == end)
|
|
return 0;
|
|
|
|
inst.cond = COND_ALWAYS;
|
|
@@ -5813,23 +5806,13 @@ opcode_lookup (char **str)
|
|
if (dot)
|
|
{
|
|
cond = str_hash_find_n (aarch64_cond_hsh, dot + 1, end - dot - 1);
|
|
- if (cond)
|
|
- {
|
|
- inst.cond = cond->value;
|
|
- *str = end;
|
|
- }
|
|
- else
|
|
- {
|
|
- *str = dot;
|
|
- return 0;
|
|
- }
|
|
+ if (!cond)
|
|
+ return 0;
|
|
+ inst.cond = cond->value;
|
|
len = dot - base;
|
|
}
|
|
else
|
|
- {
|
|
- *str = end;
|
|
- len = end - base;
|
|
- }
|
|
+ len = end - base;
|
|
|
|
if (inst.cond == COND_ALWAYS)
|
|
{
|
|
@@ -7918,7 +7901,6 @@ dump_opcode_operands (const aarch64_opcode *opcode)
|
|
void
|
|
md_assemble (char *str)
|
|
{
|
|
- char *p = str;
|
|
templates *template;
|
|
const aarch64_opcode *opcode;
|
|
aarch64_inst *inst_base;
|
|
@@ -7941,14 +7923,28 @@ md_assemble (char *str)
|
|
DEBUG_TRACE ("==============================");
|
|
DEBUG_TRACE ("Enter md_assemble with %s", str);
|
|
|
|
- template = opcode_lookup (&p);
|
|
+ /* Scan up to the end of the mnemonic, which must end in whitespace,
|
|
+ '.', or end of string. */
|
|
+ char *p = str;
|
|
+ char *dot = 0;
|
|
+ for (; is_part_of_name (*p); p++)
|
|
+ if (*p == '.' && !dot)
|
|
+ dot = p;
|
|
+
|
|
+ if (p == str)
|
|
+ {
|
|
+ as_bad (_("unknown mnemonic -- `%s'"), str);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (!dot && create_register_alias (str, p))
|
|
+ return;
|
|
+
|
|
+ template = opcode_lookup (str, dot, p);
|
|
if (!template)
|
|
{
|
|
- /* It wasn't an instruction, but it might be a register alias of
|
|
- the form alias .req reg directive. */
|
|
- if (!create_register_alias (str, p))
|
|
- as_bad (_("unknown mnemonic `%s' -- `%s'"), get_mnemonic_name (str),
|
|
- str);
|
|
+ as_bad (_("unknown mnemonic `%s' -- `%s'"), get_mnemonic_name (str),
|
|
+ str);
|
|
return;
|
|
}
|
|
|
|
diff --git a/gas/testsuite/gas/aarch64/register_aliases.d b/gas/testsuite/gas/aarch64/register_aliases.d
|
|
index eab63870..8d614b47 100644
|
|
--- a/gas/testsuite/gas/aarch64/register_aliases.d
|
|
+++ b/gas/testsuite/gas/aarch64/register_aliases.d
|
|
@@ -10,3 +10,4 @@ Disassembly of section \.text:
|
|
8: f94003b1 ldr x17, \[x29\]
|
|
c: f90003b0 str x16, \[x29\]
|
|
10: f94003b1 ldr x17, \[x29\]
|
|
+ 14: f900001f str xzr, \[x0\]
|
|
diff --git a/gas/testsuite/gas/aarch64/register_aliases.s b/gas/testsuite/gas/aarch64/register_aliases.s
|
|
index fcd06507..856be569 100644
|
|
--- a/gas/testsuite/gas/aarch64/register_aliases.s
|
|
+++ b/gas/testsuite/gas/aarch64/register_aliases.s
|
|
@@ -3,9 +3,10 @@
|
|
fp .req x29
|
|
ip0 .req x16
|
|
ip1 .req x17
|
|
+ zero .req xzr
|
|
add ip0, ip0, lr
|
|
str ip0, [fp]
|
|
ldr ip1, [fp]
|
|
str IP0, [fp]
|
|
ldr IP1, [fp]
|
|
-
|
|
+ str zero, [x0]
|
|
diff --git a/gas/testsuite/gas/aarch64/register_aliases_invalid.d b/gas/testsuite/gas/aarch64/register_aliases_invalid.d
|
|
new file mode 100644
|
|
index 00000000..7c453ce0
|
|
--- /dev/null
|
|
+++ b/gas/testsuite/gas/aarch64/register_aliases_invalid.d
|
|
@@ -0,0 +1 @@
|
|
+#error_output: register_aliases_invalid.l
|
|
diff --git a/gas/testsuite/gas/aarch64/register_aliases_invalid.l b/gas/testsuite/gas/aarch64/register_aliases_invalid.l
|
|
new file mode 100644
|
|
index 00000000..6350049d
|
|
--- /dev/null
|
|
+++ b/gas/testsuite/gas/aarch64/register_aliases_invalid.l
|
|
@@ -0,0 +1,3 @@
|
|
+.*:
|
|
+.*: Error: unknown mnemonic `lr\.req' -- `lr\.req x30'
|
|
+.*: Error: unknown mnemonic `lr\.a' -- `lr\.a .req x30'
|
|
diff --git a/gas/testsuite/gas/aarch64/register_aliases_invalid.s b/gas/testsuite/gas/aarch64/register_aliases_invalid.s
|
|
new file mode 100644
|
|
index 00000000..2df2eaab
|
|
--- /dev/null
|
|
+++ b/gas/testsuite/gas/aarch64/register_aliases_invalid.s
|
|
@@ -0,0 +1,2 @@
|
|
+lr.req x30
|
|
+lr.a .req x30
|
|
--
|
|
2.19.1
|
|
|