Writing and Loading Your First eBPF Program in C and LLVM/Clang
Part I: The Article
The Linux kernel has always had a tension between observability and stability. Kernel modules let you run arbitrary code in ring 0—powerful, but a single null dereference takes down the machine. Kernel developers spent decades building safer tracing infrastructure: kprobes, tracepoints, the perf subsystem. Then eBPF arrived and changed the terms of the deal.
eBPF is a restricted virtual machine embedded in the kernel. You write C, compile it to BPF bytecode with LLVM/Clang, hand it to the kernel, and the verifier checks every instruction before the JIT compiler turns it into native code. No module signing, no kernel rebuild, no reboot. The program runs in kernel context with access to a curated set of helper functions and can read kernel data structures—but it cannot call arbitrary kernel functions, write to arbitrary memory, or loop without bound.
The BPF Virtual Machine
The BPF ISA has 11 64-bit registers (r0 through r10), a 512-byte stack, and around 100 instructions. r10 is the frame pointer (read-only). r0 holds the return value. r1 through r5 carry function arguments. r1 is set by the kernel before your program runs to point at the context—the tracepoint arguments, the
xdp_mddescriptor, the__sk_buff, whatever your program type expects.The 512-byte stack is not a soft guideline. The verifier tracks every stack write and counts the bytes. Declare a
char filename[600]on the BPF stack and clang will refuse to compile it. This is the first place people run into trouble: you cannot do a recursive string walk, you cannot build a large working buffer, you cannot hold two 300-byte arrays simultaneously. The solution is either per-CPU array maps used as scratch space or reserving memory directly from the ring buffer before you fill it.


