github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/docs/ebpf/guides/portable-ebpf.md (about) 1 # Shipping Portable eBPF-powered Applications 2 3 !!! incomplete 4 This guide builds on Getting Started. 5 6 Document what the various ways are for making tools portable across kernel 7 versions and what the various CO-RE techniques are. 8 9 !!! tip "" 10 We recommend building eBPF C code from within a container with a stable LLVM 11 toolchain, as well as checking all generated `.o` and `.go` files into 12 source control. This buys you fully-reproducible builds, prevents bugs due 13 to team members using different LLVM versions and makes your packages fully 14 independent and `go run`nable. It also prevents PII from leaking into ELFs 15 in the form of absolute paths to `.c` source files in DWARF info. 16 17 ### Cross-compiling 18 19 You may have noticed bpf2go generating two sets of files: 20 21 - `*_bpfel.o` and `*_bpfel.go` for little-endian architectures like amd64, 22 arm64, riscv64 and loong64 23 - `*_bpfeb.o` and `*_bpfeb.go` for big-endian architectures like s390(x), mips 24 and sparc 25 26 Both sets of .go files contain a `//go:embed` statement that slurps the contents 27 of the respective .o files into a byte slice at compile time. The result is a 28 standalone Go application binary that can be deployed to a target machine 29 without any of the .o files included. To further reduce runtime dependencies, 30 add `CGO_ENABLED=0` to `go build` and your application won't depend on libc. 31 (assuming none of your other dependencies require cgo) 32 33 Moreover, because both eBPF objects and Go scaffolding are generated for both 34 big- and little-endian architectures, cross-compiling your Go application is as 35 simple as setting the right `GOARCH` value at compile time. 36 37 Pulling it all together, for building an eBPF-powered Go application for a 38 Raspberry Pi running a 64-bit Linux distribution: 39 40 ```shell-session 41 CGO_ENABLED=0 GOARCH=arm64 go build 42 ``` 43 44 ### Compile Once - Run Everywhere? 45 46 Since we can generate a standalone binary and deploy it to any system, does that 47 mean tools built using {{ proj }} will magically work anywhere? Unfortunately, 48 no, not really. 49 50 The kernel's internal data structures change as the kernel progresses in 51 development, just like any other software. Differences in compile-time 52 configuration affect data structures and the presence of certain kernel symbols. 53 This means that, even when using the exact same kernel release, no two Linux 54 distributions will be the same when it comes to data layout. 55 56 This is problematic for authors that want to ship a single binary to their users 57 and expect it to work across multiple distributions and kernel versions. In 58 response to this, the term *Compile Once - Run Everywhere* was coined to 59 describe the collection of techniques employed to achieve universal 60 interoperability for eBPF. This technique relies on type information encoded in 61 BPF Type Format (BTF) to be shipped with the kernel so memory accesses can be 62 adjusted right before loading the eBPF program into the kernel. 63 64 Alternatively, you may opt for shipping a full LLVM compiler toolchain along 65 with your application and recompiling the eBPF C against Linux kernel headers 66 present on the target machine. This approach is out of scope of the {{ proj }} 67 documentation.