mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-01-30 12:44:10 +08:00
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:
parent
26c7a0ea38
commit
8fbb497b72
@ -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
|
||||
|
@ -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', ®no)
|
||||
|| parse_bpf_register ((char *) name, 'w', ®no))
|
||||
{
|
||||
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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
3
gas/testsuite/gas/bpf/regs-for-symbols-pseudoc.d
Normal file
3
gas/testsuite/gas/bpf/regs-for-symbols-pseudoc.d
Normal file
@ -0,0 +1,3 @@
|
||||
#as: -EL -mdialect=pseudoc
|
||||
#source: regs-for-symbols-pseudoc.s
|
||||
#error_output: regs-for-symbols-pseudoc.l
|
8
gas/testsuite/gas/bpf/regs-for-symbols-pseudoc.l
Normal file
8
gas/testsuite/gas/bpf/regs-for-symbols-pseudoc.l
Normal 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
|
4
gas/testsuite/gas/bpf/regs-for-symbols-pseudoc.s
Normal file
4
gas/testsuite/gas/bpf/regs-for-symbols-pseudoc.s
Normal file
@ -0,0 +1,4 @@
|
||||
goto w3
|
||||
r2 = r3 ll
|
||||
r2 = r3+1 ll
|
||||
r2 = 1+r3 ll
|
Loading…
Reference in New Issue
Block a user