BPF (Berkeley Packet Filter) is a register-based VM (virtual machine) most often used by Unix-like kernels (e.g. the various BSDs and Linux) for running user-specified network analysis programs (packet filters) in kernel space (for performance). The eBPF (extended BPF) flavor adds a bunch of new features, including embiggening the VM’s register count (from 2 to 10 general purpose registers and 1 read-only frame pointer) and register width (32-bit to 64-bit).
Recent clang and gcc compilers can compile C code to eBPF bytecode. The script below literally says -target bpf but the output is eBPF.
The calling convention is up to 5 function arguments are passed in registers r1, r2, ..., r5 and the return value is passed back in register r0.
Kernel API that take arbitrary eBPF programs will typically verify that they’re safe to run, before actually running them. Safety includes ensuring that the eBPF program won’t run forever and one easy way to enforce that is having no backwards jumps (jumps with negative offsets). In general, though, eBPF isn’t restricted to the kernel and eBPF programs can contain infinite loops.
eBPF can also represent calls to user-defined functions (although some kernel verifiers may reject them, depending on the kernel version). Like jumps, the call instruction’s argument (‘immediate’ for calls, ‘offset’ for jumps) is relative to the multiple-of-8-bytes position after the jump or call instruction. If the compiler emits bytecode in the same order that functions are defined in the source code then the argument can be negative or positive depending on whether the callee implementation is before or after the call instruction.