[PATCH] bpf: add may_goto instruction [PR32176]

Jose E. Marchesi jemarch@gnu.org
Thu Feb 5 20:01:24 GMT 2026


Hi David.
Thanks for the patch.

OK.

> The BPF "may_goto" instruction is a special sort of conditional jump
> where the condition is determined by the BPF runtime.  That is, it is
> a no-op until the runtime decides otherwise.
>
> For normal asm syntax, the mnemonic "jcond" is chosen in keeping with
> the style of following the opcode definitions in the Linux kernel uapi
> BPF headers.
>
> This instruction is not currently emitted by GCC, but it can be inserted
> into BPF programs via macros defined in the Linux kernel.
>
> Tested on x86_64-linux-gnu for bpf-unknown-none.
> Sanity checked building Linux kernel bpf-next selftests.
>
> 	PR gas/32176
>
> include/
> 	* opcode/bpf.h (BPF_CODE_JCOND): New.
> 	(bpf_insn_id): Add BPF_INSN_JCOND.
>
> opcodes/
> 	* bpf-opc.c: Add entry for BPF_INSN_JCOND.
>
> gas/testsuite/
> 	* gas/bpf/bpf.exp: Run new dump tests.
> 	* gas/bpf/jcond-be-pseudoc.d: New.
> 	* gas/bpf/jcond-be.d: New.
> 	* gas/bpf/jcond-pseudoc.d: New.
> 	* gas/bpf/jcond-pseudoc.s: New.
> 	* gas/bpf/jcond.d: New.
> 	* gas/bpf/jcond.s: New.
> ---
>  gas/testsuite/gas/bpf/bpf.exp            |  6 ++++++
>  gas/testsuite/gas/bpf/jcond-be-pseudoc.d | 14 ++++++++++++++
>  gas/testsuite/gas/bpf/jcond-be.d         | 14 ++++++++++++++
>  gas/testsuite/gas/bpf/jcond-pseudoc.d    | 14 ++++++++++++++
>  gas/testsuite/gas/bpf/jcond-pseudoc.s    |  8 ++++++++
>  gas/testsuite/gas/bpf/jcond.d            | 14 ++++++++++++++
>  gas/testsuite/gas/bpf/jcond.s            |  8 ++++++++
>  include/opcode/bpf.h                     |  4 ++++
>  opcodes/bpf-opc.c                        |  4 ++++
>  9 files changed, 86 insertions(+)
>  create mode 100644 gas/testsuite/gas/bpf/jcond-be-pseudoc.d
>  create mode 100644 gas/testsuite/gas/bpf/jcond-be.d
>  create mode 100644 gas/testsuite/gas/bpf/jcond-pseudoc.d
>  create mode 100644 gas/testsuite/gas/bpf/jcond-pseudoc.s
>  create mode 100644 gas/testsuite/gas/bpf/jcond.d
>  create mode 100644 gas/testsuite/gas/bpf/jcond.s
>
> diff --git a/gas/testsuite/gas/bpf/bpf.exp b/gas/testsuite/gas/bpf/bpf.exp
> index 89955e1a9e4..f1932212252 100644
> --- a/gas/testsuite/gas/bpf/bpf.exp
> +++ b/gas/testsuite/gas/bpf/bpf.exp
> @@ -47,6 +47,9 @@ if {[istarget bpf*-*-*]} {
>      run_dump_test jump-relax-ja
>      run_dump_test jump-relax-jump
>  
> +    run_dump_test jcond
> +    run_dump_test jcond-pseudoc
> +
>      # Big-endian BPF tests
>      run_dump_test call-be
>      run_dump_test exit-be
> @@ -70,6 +73,9 @@ if {[istarget bpf*-*-*]} {
>      run_dump_test jump-relax-ja-be
>      run_dump_test jump-relax-jump-be
>  
> +    run_dump_test jcond-be
> +    run_dump_test jcond-be-pseudoc
> +
>      # Overflow tests
>      run_dump_test offset16-overflow
>      run_dump_test disp16-overflow
> diff --git a/gas/testsuite/gas/bpf/jcond-be-pseudoc.d b/gas/testsuite/gas/bpf/jcond-be-pseudoc.d
> new file mode 100644
> index 00000000000..5bd24e194a7
> --- /dev/null
> +++ b/gas/testsuite/gas/bpf/jcond-be-pseudoc.d
> @@ -0,0 +1,14 @@
> +#as: -EB -mdialect=pseudoc
> +#objdump: -dr -M dec,pseudoc
> +#source: jcond-pseudoc.s
> +#name: BPF conditional pseudo-jump instruction, pseudoc syntax, big-endian
> +
> +.*: +file format .*bpf.*
> +
> +Disassembly of section .text:
> +
> +0+ <.text>:
> +   0:	e5 00 00 00 00 00 00 00 	may_goto 0
> +   8:	e5 00 00 01 00 00 00 00 	may_goto 1
> +  10:	e5 00 ff fe 00 00 00 00 	may_goto -2
> +  18:	e5 00 ff fd 00 00 00 00 	may_goto -3
> diff --git a/gas/testsuite/gas/bpf/jcond-be.d b/gas/testsuite/gas/bpf/jcond-be.d
> new file mode 100644
> index 00000000000..da2cfbaf481
> --- /dev/null
> +++ b/gas/testsuite/gas/bpf/jcond-be.d
> @@ -0,0 +1,14 @@
> +#as: -EB -mdialect=normal
> +#objdump: -dr -M dec
> +#source: jcond.s
> +#name: BPF conditional pseudo-jump instruction, normal syntax, big-endian
> +
> +.*: +file format .*bpf.*
> +
> +Disassembly of section .text:
> +
> +0+ <.text>:
> +   0:	e5 00 00 00 00 00 00 00 	jcond 0
> +   8:	e5 00 00 01 00 00 00 00 	jcond 1
> +  10:	e5 00 ff fe 00 00 00 00 	jcond -2
> +  18:	e5 00 ff fd 00 00 00 00 	jcond -3
> diff --git a/gas/testsuite/gas/bpf/jcond-pseudoc.d b/gas/testsuite/gas/bpf/jcond-pseudoc.d
> new file mode 100644
> index 00000000000..34c14c2bdd2
> --- /dev/null
> +++ b/gas/testsuite/gas/bpf/jcond-pseudoc.d
> @@ -0,0 +1,14 @@
> +#as: -EL -mdialect=pseudoc
> +#objdump: -dr -M dec,pseudoc
> +#source: jcond-pseudoc.s
> +#name: BPF conditional pseudo-jump instruction, pseudoc syntax
> +
> +.*: +file format .*bpf.*
> +
> +Disassembly of section .text:
> +
> +0+ <.text>:
> +   0:	e5 00 00 00 00 00 00 00 	may_goto 0
> +   8:	e5 00 01 00 00 00 00 00 	may_goto 1
> +  10:	e5 00 fe ff 00 00 00 00 	may_goto -2
> +  18:	e5 00 fd ff 00 00 00 00 	may_goto -3
> diff --git a/gas/testsuite/gas/bpf/jcond-pseudoc.s b/gas/testsuite/gas/bpf/jcond-pseudoc.s
> new file mode 100644
> index 00000000000..b48ef38d97a
> --- /dev/null
> +++ b/gas/testsuite/gas/bpf/jcond-pseudoc.s
> @@ -0,0 +1,8 @@
> +# Test for conditional pseudo-jump instruction in pseudo-c syntax
> +    .text
> +    may_goto 1f
> +1:
> +    may_goto 2f
> +    may_goto 1b
> +2:
> +    may_goto 1b
> diff --git a/gas/testsuite/gas/bpf/jcond.d b/gas/testsuite/gas/bpf/jcond.d
> new file mode 100644
> index 00000000000..69570e2f4d8
> --- /dev/null
> +++ b/gas/testsuite/gas/bpf/jcond.d
> @@ -0,0 +1,14 @@
> +#as: -EL -mdialect=normal
> +#objdump: -dr -M dec
> +#source: jcond.s
> +#name: BPF conditional pseudo-jump instruction, normal syntax, little-endian
> +
> +.*: +file format .*bpf.*
> +
> +Disassembly of section .text:
> +
> +0+ <.text>:
> +   0:	e5 00 00 00 00 00 00 00 	jcond 0
> +   8:	e5 00 01 00 00 00 00 00 	jcond 1
> +  10:	e5 00 fe ff 00 00 00 00 	jcond -2
> +  18:	e5 00 fd ff 00 00 00 00 	jcond -3
> diff --git a/gas/testsuite/gas/bpf/jcond.s b/gas/testsuite/gas/bpf/jcond.s
> new file mode 100644
> index 00000000000..9c61644ca18
> --- /dev/null
> +++ b/gas/testsuite/gas/bpf/jcond.s
> @@ -0,0 +1,8 @@
> +# Test for conditional pseudo-jump instruction
> +    .text
> +    jcond 1f
> +1:
> +    jcond 2f
> +    jcond 1b
> +2:
> +    jcond 1b
> diff --git a/include/opcode/bpf.h b/include/opcode/bpf.h
> index d4d4f6d8557..e4ccd430f0c 100644
> --- a/include/opcode/bpf.h
> +++ b/include/opcode/bpf.h
> @@ -106,6 +106,7 @@ typedef uint64_t bpf_insn_word;
>  #define BPF_CODE_JLE  ((uint64_t)0xb0 << 56)
>  #define BPF_CODE_JSLT ((uint64_t)0xc0 << 56)
>  #define BPF_CODE_JSLE ((uint64_t)0xd0 << 56)
> +#define BPF_CODE_JCOND ((uint64_t)0xe0 << 56)
>  
>  #define BPF_MODE_IMM  ((uint64_t)0x00 << 56)
>  #define BPF_MODE_ABS  ((uint64_t)0x20 << 56)
> @@ -229,6 +230,9 @@ enum bpf_insn_id
>    BPF_INSN_ACMP, BPF_INSN_AXCHG,
>    /* Atomic compare-and-swap, atomic exchange (32-bit).  */
>    BPF_INSN_ACMP32, BPF_INSN_AXCHG32,
> +  /* Conditional pseudo-jump "may_goto".  A NOP until the BPF runtime
> +     decides it isn't.  */
> +  BPF_INSN_JCOND,
>    /* GNU simulator specific instruction.  */
>    BPF_INSN_BRKPT,
>  };
> diff --git a/opcodes/bpf-opc.c b/opcodes/bpf-opc.c
> index 91ee561ea10..aa5493280ea 100644
> --- a/opcodes/bpf-opc.c
> +++ b/opcodes/bpf-opc.c
> @@ -413,6 +413,10 @@ const struct bpf_opcode bpf_opcodes[] =
>    {BPF_INSN_AADD32, "xaddw%W[ %dr %o16 ] , %sr", "* ( u32 * ) ( %dr %o16 ) += %sr",
>     BPF_V1, BPF_CODE|BPF_IMM32, BPF_CLASS_STX|BPF_SIZE_W|BPF_MODE_ATOMIC|BPF_IMM32_AADD},
>  
> +  /* The "conditional pseudo-jump" instruction, a.k.a. "may_goto".  */
> +  {BPF_INSN_JCOND, "jcond%W%d16", "may_goto%w%d16",
> +   BPF_V4, BPF_CODE|BPF_IMM32, BPF_CLASS_JMP|BPF_CODE_JCOND|BPF_SRC_K},
> +
>    /* the brkpt instruction is used by the BPF simulator and it doesn't
>       really belong to the BPF instruction set.  */
>    {BPF_INSN_BRKPT, "brkpt", "brkpt",


More information about the Binutils mailing list