[PATCH] bpf: add may_goto instruction [PR32176]
David Faust
david.faust@oracle.com
Thu Feb 5 20:30:59 GMT 2026
On 2/5/26 12:01, Jose E. Marchesi wrote:
>
> Hi David.
> Thanks for the patch.
Pushed as git bdb4d0030dedaaf18f09690218a2896ea57a4cdd
Thanks.
>
> 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