https://gcc.gnu.org/g:ffe3ead4a8ad704b557b0cfa4f823df647c65a0d
commit r17-5013-gffe3ead4a8ad704b557b0cfa4f823df647c65a0d Author: Vineet Gupta <[email protected]> Date: Fri Oct 9 14:15:07 2026 +0530 bpf: add -mcallx, enabled for CPU v1 and above Indirect calls were only generated with -mxbpf, and otherwise diagnosed as an error. The `callx' instruction is however part of the BPF CPU v1 ISA, and is accepted by the assembler for v1 without -mxbpf. It is also emitted by LLVM for all CPU versions. Make it an ISA feature like the others: add -mcallx/-mno-callx, enabled by default for CPU v1 and above, i.e. always, along with the corresponding __BPF_FEATURE_CALLX macro. -mno-callx restores the old behaviour of diagnosing indirect calls. This was the last user of TARGET_XBPF in the compiler; -mxbpf is now only passed on to the assembler. Document it as such, which also drops the only effect its documentation listed, the saving and restoring of callee-saved registers, removed in r11-490-g98456a64b0b5. gcc/ChangeLog: * config/bpf/bpf.opt (mcallx): New option. * config/bpf/bpf.cc (bpf_option_override): Enable bpf_has_callx for CPU v1 and above. (bpf_output_call): Check bpf_has_callx instead of TARGET_XBPF. (bpf_small_register_classes_for_mode_p): Likewise. * config/bpf/bpf-c.cc (bpf_target_macros): Define __BPF_FEATURE_CALLX. * config/bpf/bpf.md (call_internal): Update comment. * doc/invoke.texi (eBPF Options): Document -mcallx. Document that -mxbpf is only passed on to the assembler, and remove the stale note about callee-saved registers. gcc/testsuite/ChangeLog: * gcc.target/bpf/diag-indcalls.c: Pass -mno-callx. * gcc.target/bpf/feature-macro-1.c: Pass -mcallx and check __BPF_FEATURE_CALLX. * gcc.target/bpf/feature-macro-3.c: New test. * gcc.target/bpf/feature-macro-4.c: New test. * gcc.target/bpf/indirect-call-1.c: New test. * gcc.target/bpf/indirect-call-2.c: New test. Signed-off-by: Vineet Gupta <[email protected]> Diff: --- gcc/config/bpf/bpf-c.cc | 2 ++ gcc/config/bpf/bpf.cc | 12 +++++++----- gcc/config/bpf/bpf.md | 2 +- gcc/config/bpf/bpf.opt | 4 ++++ gcc/doc/invoke.texi | 27 ++++++++++++++++++-------- gcc/testsuite/gcc.target/bpf/diag-indcalls.c | 2 +- gcc/testsuite/gcc.target/bpf/feature-macro-1.c | 6 +++++- gcc/testsuite/gcc.target/bpf/feature-macro-3.c | 6 ++++++ gcc/testsuite/gcc.target/bpf/feature-macro-4.c | 6 ++++++ gcc/testsuite/gcc.target/bpf/indirect-call-1.c | 21 ++++++++++++++++++++ gcc/testsuite/gcc.target/bpf/indirect-call-2.c | 22 +++++++++++++++++++++ 11 files changed, 94 insertions(+), 16 deletions(-) diff --git a/gcc/config/bpf/bpf-c.cc b/gcc/config/bpf/bpf-c.cc index d80c5fdf4f18..33b15f44daaf 100644 --- a/gcc/config/bpf/bpf-c.cc +++ b/gcc/config/bpf/bpf-c.cc @@ -76,6 +76,8 @@ bpf_target_macros (cpp_reader *pfile) builtin_define ("__BPF_FEATURE_SDIV_SMOD"); if (bpf_has_smov) builtin_define ("__BPF_FEATURE_MOVSX"); + if (bpf_has_callx) + builtin_define ("__BPF_FEATURE_CALLX"); /* Other CPU features can only be enabled/disabled generically by selecting the corresponding CPU version. */ diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc index b7227f1c135c..d63341022f4d 100644 --- a/gcc/config/bpf/bpf.cc +++ b/gcc/config/bpf/bpf.cc @@ -248,6 +248,9 @@ bpf_option_override (void) if (bpf_has_smov == -1) bpf_has_smov = (bpf_isa >= ISA_V4); + if (bpf_has_callx == -1) + bpf_has_callx = (bpf_isa >= ISA_V1); + /* Disable -fstack-protector as it is not supported in BPF. */ if (flag_stack_protect) { @@ -759,8 +762,7 @@ bpf_output_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED) is an RTX denoting the address of the called function. The main purposes of this function are: - - To reject indirect CALL instructions, which are not supported by - eBPF, unless targeting xBPF. + - To reject indirect CALL instructions when disabled by -mno-callx. - To recognize calls to kernel helper functions and emit the corresponding CALL N instruction. @@ -792,7 +794,7 @@ bpf_output_call (const char *templ, rtx *operands, int target_index) break; } default: - if (!TARGET_XBPF) + if (!bpf_has_callx) { error ("indirect call in function, which are not supported by eBPF"); operands[target_index] = GEN_INT (0); @@ -1317,11 +1319,11 @@ bpf_asm_named_section (const char *name, unsigned int flags, static bool bpf_small_register_classes_for_mode_p (machine_mode mode) { - if (TARGET_XBPF) + if (bpf_has_callx) return 1; else /* Avoid putting function addresses in registers, as calling these - is not supported in eBPF. */ + is not supported with -mno-callx. */ return (mode != FUNCTION_MODE); } diff --git a/gcc/config/bpf/bpf.md b/gcc/config/bpf/bpf.md index a577b494133f..15d0f95cf0d0 100644 --- a/gcc/config/bpf/bpf.md +++ b/gcc/config/bpf/bpf.md @@ -540,7 +540,7 @@ }) ;; Emit a direct call for a constant address (S), or an indirect call -;; for a register (r), the latter only generated when targeting xBPF. +;; for a register (r), the latter unless disabled by -mno-callx. ;; Indirect calls are spelled `callx rN' in the pseudo-C dialect but ;; `call %rN' in the normal one. (define_insn "call_internal" diff --git a/gcc/config/bpf/bpf.opt b/gcc/config/bpf/bpf.opt index 7d948119586f..70e2170a784c 100644 --- a/gcc/config/bpf/bpf.opt +++ b/gcc/config/bpf/bpf.opt @@ -75,6 +75,10 @@ msmov Target Var(bpf_has_smov) Init(-1) Enable signed move and memory load instructions. +mcallx +Target Var(bpf_has_callx) Init(-1) +Enable indirect call instructions. + mcpu= Target RejectNegative Joined Var(bpf_isa) Enum(bpf_isa) Init(ISA_V4) Select the eBPF ISA version to target in code generation. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 272ad0cb6f1b..66d80f17e740 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1089,7 +1089,7 @@ Objective-C and Objective-C++ Dialects}. @emph{eBPF Options} (@ref{eBPF Options}) @gccoptlist{-mbig-endian -mlittle-endian -mframe-limit=@var{bytes} -mxbpf -mco-re -mjmpext -mjmp32 --malu32 -mv3-atomics -mbswap -msdiv -msmov -mcpu=@var{version} +-malu32 -mv3-atomics -mbswap -msdiv -msmov -mcallx -mcpu=@var{version} -masm=@var{dialect} -minline-memops-threshold=@var{bytes} -Wco-re} @@ -26723,6 +26723,16 @@ CPU v4 and above. Enable or disable sign-extending move and memory load instructions. Enabled for CPU v4 and above. +@opindex mcallx +@opindex mno-callx +@item -mcallx +@itemx -mno-callx +Enable or disable indirect call instructions, 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. With @option{-mno-callx} an indirect call is +diagnosed as an error. Enabled for CPU v1 and above. + @opindex mcpu @item -mcpu=@var{version} This specifies which version of the eBPF ISA to target. Newer versions @@ -26732,7 +26742,8 @@ Supported values for @var{version} are: @table @samp @item v1 -The first stable eBPF ISA with no special features or extensions. +The first stable eBPF ISA. Supports indirect calls, as in +@option{-mcallx}. @item v2 Supports the jump extensions, as in @option{-mjmpext}. @@ -26765,12 +26776,12 @@ information for the BPF target (@option{-gbtf}). @opindex mxbpf @opindex mno-xbpf @item -mxbpf -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. -@end itemize +Target xBPF, an expanded version of BPF which relaxes some of the +restrictions imposed by the BPF architecture. This option does not +currently affect code generation: it is 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 using such instructions is +not accepted by the kernel BPF verifier. @opindex masm=@var{dialect} @item -masm=@var{dialect} diff --git a/gcc/testsuite/gcc.target/bpf/diag-indcalls.c b/gcc/testsuite/gcc.target/bpf/diag-indcalls.c index 9263fcf7e1a3..e83b03fd9987 100644 --- a/gcc/testsuite/gcc.target/bpf/diag-indcalls.c +++ b/gcc/testsuite/gcc.target/bpf/diag-indcalls.c @@ -1,6 +1,6 @@ /* Verify proper errors are generated for indirect function calls. */ /* { dg-do compile } */ -/* { dg-options "-O0" } */ +/* { dg-options "-O0 -mno-callx" } */ void (*fnp) (void); diff --git a/gcc/testsuite/gcc.target/bpf/feature-macro-1.c b/gcc/testsuite/gcc.target/bpf/feature-macro-1.c index 5fa7d3f46a2a..dc099360038f 100644 --- a/gcc/testsuite/gcc.target/bpf/feature-macro-1.c +++ b/gcc/testsuite/gcc.target/bpf/feature-macro-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-mcpu=v1 -malu32 -mjmp32 -mjmpext -mbswap -msdiv -msmov" } */ +/* { dg-options "-mcpu=v1 -malu32 -mjmp32 -mjmpext -mbswap -msdiv -msmov -mcallx" } */ #ifndef __BPF_FEATURE_ALU32 #error __BPF_FEATURE_ALU32 undefined @@ -21,6 +21,10 @@ #error __BPF_FEATURE_MOVSX undefined #endif +#ifndef __BPF_FEATURE_CALLX +#error __BPF_FEATURE_CALLX undefined +#endif + #ifdef __BPF_FEATURE_LDSX #error __BPF_FEATURE_LDSX defined with -mcpu=v1 #endif diff --git a/gcc/testsuite/gcc.target/bpf/feature-macro-3.c b/gcc/testsuite/gcc.target/bpf/feature-macro-3.c new file mode 100644 index 000000000000..bd63fac2e8c9 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/feature-macro-3.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-mcpu=v1" } */ + +#ifndef __BPF_FEATURE_CALLX +#error __BPF_FEATURE_CALLX undefined with -mcpu=v1 +#endif diff --git a/gcc/testsuite/gcc.target/bpf/feature-macro-4.c b/gcc/testsuite/gcc.target/bpf/feature-macro-4.c new file mode 100644 index 000000000000..b1254abe7d06 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/feature-macro-4.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-mno-callx" } */ + +#ifdef __BPF_FEATURE_CALLX +#error __BPF_FEATURE_CALLX defined with -mno-callx +#endif diff --git a/gcc/testsuite/gcc.target/bpf/indirect-call-1.c b/gcc/testsuite/gcc.target/bpf/indirect-call-1.c new file mode 100644 index 000000000000..916f886043a8 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/indirect-call-1.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-mcpu=v1 -masm=normal" } */ + +/* GCC should generate an indirect call instruction (call %REG) for + CPU v1 and above, without -mxbpf. */ + +void +foo () +{ + ; +} + +void +bar() +{ + void (*funp) () = &foo; + + (*funp) (); +} + +/* { dg-final { scan-assembler "call\t%r" } } */ diff --git a/gcc/testsuite/gcc.target/bpf/indirect-call-2.c b/gcc/testsuite/gcc.target/bpf/indirect-call-2.c new file mode 100644 index 000000000000..9f3a5a6361b8 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/indirect-call-2.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-mcpu=v1 -masm=pseudoc" } */ + +/* GCC should generate an indirect call instruction (callx REG) for + CPU v1 and above, without -mxbpf. */ + +void +foo () +{ + ; +} + +void +bar() +{ + void (*funp) () = &foo; + + (*funp) (); +} + +/* { dg-final { scan-assembler "callx\tr" } } */ +/* { dg-final { scan-assembler-not "call\tr" } } */
