[PATCH 1/2] bpf: spell xBPF indirect calls `callx' in the pseudo-C dialect
Vineet Gupta
vineet.gupta@linux.dev
Fri Sep 25 18:38:36 GMT 2026
An indirect call is spelled `callx rN' in the pseudo-C dialect but
`call %rN' in the normal one. The call patterns however
emitted a single `call\t%N' template for both dialects,
so a function pointer call built with -mxbpf could not be assembled
because Pseudo-C is the default:
$ bpf-unknown-none-gcc -mxbpf -O2 -c callx.c
Error: unexpected register name `r0' in instruction `call r0'
The only existing test for this, xbpf-indirect-call-1.c, passes
-masm=normal and so did not catch it.
A direct call is spelled `call' in both dialects, so the template cannot
simply be turned into an alternation. Instead split the call target
constraint, which already distinguishes a constant call address (S) from
a register, into two alternatives and give each its own template.
While at it, fix the -mxbpf documentation: the only effect it listed was
the saving and restoring of callee-saved registers in the prologue,
removed in r11-490-g98456a64b0b5, and the indirect calls it does enable
were not documented at all.
gcc/ChangeLog:
* config/bpf/bpf.md (call_internal): Split the call target
constraint into separate alternatives for a constant address and
for a register, and use the pseudo-C spelling `callx' for the
latter.
(call_value_internal): Likewise.
* config/bpf/bpf.cc (bpf_output_call): Update comment.
* doc/invoke.texi (eBPF Options): Document that -mxbpf enables
indirect calls and is passed on to the assembler. Remove the
stale note about callee-saved registers.
gcc/testsuite/ChangeLog:
* gcc.target/bpf/xbpf-indirect-call-2.c: New test.
Signed-off-by: Vineet Gupta <vineet.gupta@linux.dev>
xxx
---
gcc/config/bpf/bpf.cc | 2 +-
gcc/config/bpf/bpf.md | 15 ++++++++----
gcc/doc/invoke.texi | 11 +++++++--
.../gcc.target/bpf/xbpf-indirect-call-2.c | 23 +++++++++++++++++++
4 files changed, 44 insertions(+), 7 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/bpf/xbpf-indirect-call-2.c
diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
index 6bd714d50534..0e63f2c10ea0 100644
--- a/gcc/config/bpf/bpf.cc
+++ b/gcc/config/bpf/bpf.cc
@@ -760,7 +760,7 @@ bpf_output_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
The main purposes of this function are:
- To reject indirect CALL instructions, which are not supported by
- eBPF.
+ eBPF, unless targetting xBPF.
- To recognize calls to kernel helper functions and emit the
corresponding CALL N instruction.
diff --git a/gcc/config/bpf/bpf.md b/gcc/config/bpf/bpf.md
index a2bceb8998d7..541016b6f9e3 100644
--- a/gcc/config/bpf/bpf.md
+++ b/gcc/config/bpf/bpf.md
@@ -539,13 +539,18 @@
DONE;
})
+;; Indirect calls, generated when targetting xBPF.
+;; The register based are spelled differently for Pseudo-C `callx rN'
+;; vs. `call %rN' in the normal assembly dialect.
(define_insn "call_internal"
- [(call (mem:DI (match_operand:DI 0 "call_operand" "Sr"))
+ [(call (mem:DI (match_operand:DI 0 "call_operand" "S,r"))
(match_operand:SI 1 "general_operand" ""))]
;; operands[2] is next_arg_register
;; operands[3] is struct_value_size_rtx.
""
- { return bpf_output_call ("call\t%0", operands, 0); }
+ "@
+ *return bpf_output_call (\"call\t%0\", operands, 0);
+ *return bpf_output_call (\"{call\t%0|callx\t%0}\", operands, 0);"
[(set_attr "type" "jmp")])
(define_expand "call_value"
@@ -563,12 +568,14 @@
(define_insn "call_value_internal"
[(set (match_operand 0 "register_operand" "")
- (call (mem:DI (match_operand:DI 1 "call_operand" "Sr"))
+ (call (mem:DI (match_operand:DI 1 "call_operand" "S,r"))
(match_operand:SI 2 "general_operand" "")))]
;; operands[3] is next_arg_register
;; operands[4] is struct_value_size_rtx.
""
- { return bpf_output_call ("call\t%1", operands, 1); }
+ "@
+ *return bpf_output_call (\"call\t%1\", operands, 1);
+ *return bpf_output_call (\"{call\t%1|callx\t%1}\", operands, 1);"
[(set_attr "type" "jmp")])
(define_insn "sibcall"
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 2c2ed1a003fe..4acd2ba4aa8d 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -26641,10 +26641,17 @@ information for the BPF target (@option{-gbtf}).
Generate code for an expanded version of BPF, which relaxes some of
the restrictions imposed by the BPF architecture:
@itemize @minus
-@item Save and restore callee-saved registers at function entry and
-exit, respectively.
+@item Generate indirect calls, i.e.@: calls through a function pointer,
+which are emitted as @code{call %r@var{N}} in the @samp{normal} assembly
+dialect and as @code{callx r@var{N}} in the @samp{pseudoc} one. Without
+@option{-mxbpf} an indirect call is diagnosed as an error.
@end itemize
+@option{-mxbpf} is also passed on to the assembler, where it selects the
+@samp{xbpf} ISA spec and thus enables the assembly of xBPF-only
+instructions. Note that code generated for xBPF is not necessarily
+accepted by the kernel BPF verifier.
+
@opindex masm=@var{dialect}
@item -masm=@var{dialect}
Outputs assembly instructions using eBPF selected @var{dialect}. The default
diff --git a/gcc/testsuite/gcc.target/bpf/xbpf-indirect-call-2.c b/gcc/testsuite/gcc.target/bpf/xbpf-indirect-call-2.c
new file mode 100644
index 000000000000..1a7206fbf3f8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/bpf/xbpf-indirect-call-2.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-mxbpf -masm=pseudoc" } */
+
+/* GCC should generate an indirect call instruction (callx REG) when
+ targetting xBPF in the pseudo-C assembly dialect. The normal dialect
+ spelling (call %REG) is not accepted by the assembler in pseudo-C. */
+
+void
+foo ()
+{
+ ;
+}
+
+void
+bar()
+{
+ void (*funp) () = &foo;
+
+ (*funp) ();
+}
+
+/* { dg-final { scan-assembler "callx\tr" } } */
+/* { dg-final { scan-assembler-not "call\tr" } } */
--
2.53.0-Meta
More information about the bpf
mailing list