gas: bpf: do not allow referring to register names as symbols in operands

2023-11-18  Jose E. Marchesi  <jemarch@gnu.org>

	* config/tc-bpf.c (parse_bpf_register): Move before
	bpf_parse_name.
	(bpf_parse_name): Do not allow using symbols that are also
	register names as operands in pseudo-c syntax.
	* testsuite/gas/bpf/regs-for-symbols-pseudoc.d: New file.
	* testsuite/gas/bpf/regs-for-symbols-pseudoc.s: Likewise.
	* testsuite/gas/bpf/regs-for-symbols-pseudoc.l: Likewise.
	* doc/c-bpf.texi (BPF Registers): Document that it is not possible
	to refer to register names as symbols in instruction operands.
This commit is contained in:
Jose E. Marchesi 2023-11-18 18:12:44 +01:00
parent 26c7a0ea38
commit 8fbb497b72
7 changed files with 119 additions and 66 deletions

View File

@ -1,3 +1,15 @@
2023-11-18 Jose E. Marchesi <jemarch@gnu.org>
* config/tc-bpf.c (parse_bpf_register): Move before
bpf_parse_name.
(bpf_parse_name): Do not allow using symbols that are also
register names as operands in pseudo-c syntax.
* testsuite/gas/bpf/regs-for-symbols-pseudoc.d: New file.
* testsuite/gas/bpf/regs-for-symbols-pseudoc.s: Likewise.
* testsuite/gas/bpf/regs-for-symbols-pseudoc.l: Likewise.
* doc/c-bpf.texi (BPF Registers): Document that it is not possible
to refer to register names as symbols in instruction operands.
2023-11-15 YunQiang Su <yunqiang.su@cipunited.com>
* testsuite/gas/mips/mips.exp (mips_arch_create): Add "--defsym

View File

@ -1255,71 +1255,6 @@ parse_expression (char *s, expressionS *exp)
return s;
}
/* Symbols created by this parse, but not yet committed to the real
symbol table. */
static symbolS *deferred_sym_rootP;
static symbolS *deferred_sym_lastP;
/* Symbols discarded by a previous parse. Symbols cannot easily be freed
after creation, so try to recycle. */
static symbolS *orphan_sym_rootP;
static symbolS *orphan_sym_lastP;
/* Implement md_parse_name hook. Handles any symbol found in an expression.
This allows us to tentatively create symbols, before we know for sure
whether the parser is using the correct template for an instruction.
If we end up keeping the instruction, the deferred symbols are committed
to the real symbol table. This approach is modeled after the riscv port. */
bool
bpf_parse_name (const char *name, expressionS *exp, enum expr_mode mode)
{
symbolS *sym;
/* If we aren't currently parsing an instruction, don't do anything.
This prevents tampering with operands to directives. */
if (!parsing_insn_operands)
return false;
gas_assert (mode == expr_normal);
if (symbol_find (name) != NULL)
return false;
for (sym = deferred_sym_rootP; sym; sym = symbol_next (sym))
if (strcmp (name, S_GET_NAME (sym)) == 0)
break;
/* Tentatively create a symbol. */
if (!sym)
{
/* See if we can reuse a symbol discarded by a previous parse.
This may be quite common, for example when trying multiple templates
for an instruction with the first reference to a valid symbol. */
for (sym = orphan_sym_rootP; sym; sym = symbol_next (sym))
if (strcmp (name, S_GET_NAME (sym)) == 0)
{
symbol_remove (sym, &orphan_sym_rootP, &orphan_sym_lastP);
break;
}
if (!sym)
sym = symbol_create (name, undefined_section, &zero_address_frag, 0);
/* Add symbol to the deferred list. If we commit to the isntruction,
then the symbol will be inserted into to the real symbol table at
that point (in md_assemble). */
symbol_append (sym, deferred_sym_lastP, &deferred_sym_rootP,
&deferred_sym_lastP);
}
exp->X_op = O_symbol;
exp->X_add_symbol = sym;
exp->X_add_number = 0;
return true;
}
/* Parse a BPF register name and return the corresponding register
number. Return NULL in case of parse error, or a pointer to the
first character in S that is not part of the register name. */
@ -1368,6 +1303,88 @@ parse_bpf_register (char *s, char rw, uint8_t *regno)
return s;
}
/* Symbols created by this parse, but not yet committed to the real
symbol table. */
static symbolS *deferred_sym_rootP;
static symbolS *deferred_sym_lastP;
/* Symbols discarded by a previous parse. Symbols cannot easily be freed
after creation, so try to recycle. */
static symbolS *orphan_sym_rootP;
static symbolS *orphan_sym_lastP;
/* Implement md_parse_name hook. Handles any symbol found in an expression.
This allows us to tentatively create symbols, before we know for sure
whether the parser is using the correct template for an instruction.
If we end up keeping the instruction, the deferred symbols are committed
to the real symbol table. This approach is modeled after the riscv port. */
bool
bpf_parse_name (const char *name, expressionS *exp, enum expr_mode mode)
{
symbolS *sym;
/* If we aren't currently parsing an instruction, don't do anything.
This prevents tampering with operands to directives. */
if (!parsing_insn_operands)
return false;
gas_assert (mode == expr_normal);
/* Pseudo-C syntax uses unprefixed register names like r2 or w3.
Since many instructions take either a register or an
immediate/expression, we should not allow references to symbols
with these names in operands. */
if (asm_dialect == DIALECT_PSEUDOC)
{
uint8_t regno;
if (parse_bpf_register ((char *) name, 'r', &regno)
|| parse_bpf_register ((char *) name, 'w', &regno))
{
as_bad (_("unexpected register name `%s' in expression"),
name);
return false;
}
}
if (symbol_find (name) != NULL)
return false;
for (sym = deferred_sym_rootP; sym; sym = symbol_next (sym))
if (strcmp (name, S_GET_NAME (sym)) == 0)
break;
/* Tentatively create a symbol. */
if (!sym)
{
/* See if we can reuse a symbol discarded by a previous parse.
This may be quite common, for example when trying multiple templates
for an instruction with the first reference to a valid symbol. */
for (sym = orphan_sym_rootP; sym; sym = symbol_next (sym))
if (strcmp (name, S_GET_NAME (sym)) == 0)
{
symbol_remove (sym, &orphan_sym_rootP, &orphan_sym_lastP);
break;
}
if (!sym)
sym = symbol_create (name, undefined_section, &zero_address_frag, 0);
/* Add symbol to the deferred list. If we commit to the isntruction,
then the symbol will be inserted into to the real symbol table at
that point (in md_assemble). */
symbol_append (sym, deferred_sym_lastP, &deferred_sym_rootP,
&deferred_sym_lastP);
}
exp->X_op = O_symbol;
exp->X_add_symbol = sym;
exp->X_add_number = 0;
return true;
}
/* Collect a parse error message. */
static int partial_match_length = 0;

View File

@ -113,7 +113,12 @@ Read-only frame pointer register.
@noindent
Note that in the Pseudo-C syntax register names are not preceded by
@code{%} characters.
@code{%} characters. A consequence of that is that in contexts like
instruction operands, where both register names and expressions
involving symbols are expected, there is no way to disambiguate
between them. In order to keep things simple, this assembler does not
allow to refer to symbols whose names collide with register names in
instruction operands.
@node BPF Directives
@section BPF Directives

View File

@ -73,6 +73,10 @@ if {[istarget bpf*-*-*]} {
run_dump_test disp32-overflow
run_dump_test imm32-overflow
# In Pseudo-C it is not possible to refer to symbols
# as operands that have the same name than registers.
run_dump_test regs-for-symbols-pseudoc
# Test that parser does not create undefined symbols
run_dump_test asm-extra-sym-1
}

View File

@ -0,0 +1,3 @@
#as: -EL -mdialect=pseudoc
#source: regs-for-symbols-pseudoc.s
#error_output: regs-for-symbols-pseudoc.l

View File

@ -0,0 +1,8 @@
.*: Assembler messages:
.*:1: Error: unexpected register name `w3' in expression
.*:2: Error: unexpected register name `r3' in expression
.*:2: Error: unexpected register name `r3' in expression
.*:3: Error: unexpected register name `r3' in expression
.*:3: Error: unexpected register name `r3' in expression
.*:4: Error: unexpected register name `r3' in expression
.*:4: Error: unexpected register name `r3' in expression

View File

@ -0,0 +1,4 @@
goto w3
r2 = r3 ll
r2 = r3+1 ll
r2 = 1+r3 ll