aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
Diffstat (limited to 'gas')
-rw-r--r--gas/config/tc-bpf.c92
-rw-r--r--gas/config/tc-bpf.h4
-rw-r--r--gas/testsuite/gas/bpf/asm-extra-sym-1.d7
-rw-r--r--gas/testsuite/gas/bpf/asm-extra-sym-1.s1
-rw-r--r--gas/testsuite/gas/bpf/bpf.exp3
5 files changed, 107 insertions, 0 deletions
diff --git a/gas/config/tc-bpf.c b/gas/config/tc-bpf.c
index fd4144a..3122f80 100644
--- a/gas/config/tc-bpf.c
+++ b/gas/config/tc-bpf.c
@@ -1223,6 +1223,7 @@ add_relaxed_insn (struct bpf_insn *insn, expressionS *exp)
See md_operand below to see how exp_parse_failed is used. */
static int exp_parse_failed = 0;
+static bool parsing_insn_operands = false;
static char *
parse_expression (char *s, expressionS *exp)
@@ -1230,6 +1231,9 @@ parse_expression (char *s, expressionS *exp)
char *saved_input_line_pointer = input_line_pointer;
char *saved_s = s;
+ /* Wake up bpf_parse_name before the call to expression (). */
+ parsing_insn_operands = true;
+
exp_parse_failed = 0;
input_line_pointer = s;
expression (exp);
@@ -1251,6 +1255,71 @@ 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. */
@@ -1317,6 +1386,16 @@ parse_error (int length, const char *fmt, ...)
va_end (args);
partial_match_length = length;
}
+
+ /* Discard deferred symbols from the failed parse. They may potentially
+ be reused in the future from the orphan list. */
+ while (deferred_sym_rootP)
+ {
+ symbolS *sym = deferred_sym_rootP;
+ symbol_remove (sym, &deferred_sym_rootP, &deferred_sym_lastP);
+ symbol_append (sym, orphan_sym_lastP, &orphan_sym_rootP,
+ &orphan_sym_lastP);
+ }
}
/* Assemble a machine instruction in STR and emit the frags/bytes it
@@ -1606,6 +1685,10 @@ md_assemble (char *str ATTRIBUTE_UNUSED)
}
}
+ /* Mark that we are no longer parsing an instruction, bpf_parse_name does
+ not interfere with symbols in e.g. assembler directives. */
+ parsing_insn_operands = false;
+
if (opcode == NULL)
{
as_bad (_("unrecognized instruction `%s'"), str);
@@ -1622,6 +1705,15 @@ md_assemble (char *str ATTRIBUTE_UNUSED)
#undef PARSE_ERROR
+ /* Commit any symbols created while parsing the instruction. */
+ while (deferred_sym_rootP)
+ {
+ symbolS *sym = deferred_sym_rootP;
+ symbol_remove (sym, &deferred_sym_rootP, &deferred_sym_lastP);
+ symbol_append (sym, symbol_lastP, &symbol_rootP, &symbol_lastP);
+ symbol_table_insert (sym);
+ }
+
/* Generate the frags and fixups for the parsed instruction. */
if (do_relax && isa_spec >= BPF_V4 && insn.is_relaxable)
{
diff --git a/gas/config/tc-bpf.h b/gas/config/tc-bpf.h
index 9fb71ed..06096ef 100644
--- a/gas/config/tc-bpf.h
+++ b/gas/config/tc-bpf.h
@@ -51,6 +51,10 @@
a jump to offset 0 means jump to the next instruction. */
#define md_single_noop_insn "ja 0"
+#define md_parse_name(name, exp, mode, c) \
+ bpf_parse_name (name, exp, mode)
+bool bpf_parse_name (const char *, struct expressionS *, enum expr_mode);
+
#define TC_EQUAL_IN_INSN(c, s) bpf_tc_equal_in_insn ((c), (s))
extern bool bpf_tc_equal_in_insn (int, char *);
diff --git a/gas/testsuite/gas/bpf/asm-extra-sym-1.d b/gas/testsuite/gas/bpf/asm-extra-sym-1.d
new file mode 100644
index 0000000..113750d
--- /dev/null
+++ b/gas/testsuite/gas/bpf/asm-extra-sym-1.d
@@ -0,0 +1,7 @@
+#as: -EL -mdialect=pseudoc
+#nm: --numeric-sort
+#source: asm-extra-sym-1.s
+#name: BPF pseudoc no extra symbols 1
+
+# Note: there should be no output from nm.
+# Previously a bug in the BPF parser created an UND '*' symbol.
diff --git a/gas/testsuite/gas/bpf/asm-extra-sym-1.s b/gas/testsuite/gas/bpf/asm-extra-sym-1.s
new file mode 100644
index 0000000..2cfa605
--- /dev/null
+++ b/gas/testsuite/gas/bpf/asm-extra-sym-1.s
@@ -0,0 +1 @@
+ r2 = *(u32*)(r1 + 8)
diff --git a/gas/testsuite/gas/bpf/bpf.exp b/gas/testsuite/gas/bpf/bpf.exp
index 80f5a1d..fcbeccd 100644
--- a/gas/testsuite/gas/bpf/bpf.exp
+++ b/gas/testsuite/gas/bpf/bpf.exp
@@ -72,4 +72,7 @@ if {[istarget bpf*-*-*]} {
run_dump_test disp16-overflow-relax
run_dump_test disp32-overflow
run_dump_test imm32-overflow
+
+ # Test that parser does not create undefined symbols
+ run_dump_test asm-extra-sym-1
}