Mastering Pure C eBPF Compilation from Kernel Source: A Step‑by‑Step Guide
This article walks you through the complete process of compiling pure‑C eBPF programs using the Linux 4.18 kernel source, covering environment setup, kernel source acquisition, essential build steps, detailed make command analysis, and verification of both user‑space and kernel‑space components.
1. Introduction
Understanding and mastering pure‑C eBPF compilation deepens knowledge of eBPF principles and enables development of high‑performance eBPF programs tailored to specific business needs.
2. Acquiring the Kernel Source
Most servers run CentOS 8 + 4.18 kernel; we recommend using this version. If you lack a compatible OS, you can purchase a CentOS 8 or Anolis 8 instance from Alibaba Cloud.
$ cat /etc/centos-release
CentOS Linux release 8.5.2111
$ uname -r
4.18.0-348.7.1.el8_5.x86_64Download the 4.18 source:
$ cd /tmp/
$ wget https://mirrors.aliyun.com/linux-kernel/v4.x/linux-4.18.tar.gz
$ tar -zxvf linux-4.18.tar.gz
$ cd linux-4.18Ensure the kernel version matches the OS because eBPF checks VERSION, PATCHLEVEL, and SUBLEVEL macros.
$ cat Makefile | grep -P '^VERSION|^PATCHLEVEL|^SUBLEVEL'
VERSION = 4
PATCHLEVEL = 18
SUBLEVEL = 03. Initializing the Basic Environment
Install required packages:
$ sudo yum install bison flex openssl-devel
$ sudo yum install clang llvm elfutils-libelf-devel4. Compiling the Kernel‑Source eBPF Sample
Initialize the kernel build environment:
$ cd /tmp/linux-4.18
$ make oldconfig && make init
$ make headers_installCompile the user‑space part of the sample:
$ make M=samples/bpf
$ gcc -g -fPIC -c -o libbpf.o libbpf.c
$ gcc -g -fPIC -c -o bpf.o bpf.c
$ gcc -g -fPIC -c -o btf.o btf.c
$ gcc -g -fPIC -c -o nlattr.o nlattr.c
$ ld -r -o libbpf-in.o libbpf.o bpf.o nlattr.o btf.o
$ ar rcs libbpf.a libbpf-in.o
$ gcc -O2 -std=gnu89 -c -o bpf_load.o bpf_load.c
$ gcc -O2 -std=gnu89 -c -o trace_output_user.o trace_output_user.c
$ gcc -O2 -std=gnu89 -c -o trace_helpers.o trace_helpers.c
$ gcc -o trace_output bpf_load.o trace_output_user.o trace_helpers.o libbpf.a -lelf -lrt
$ clang -O2 -emit-llvm -c trace_output_kern.c -o - | llc -march=bpf -filetype=obj -o trace_output_kern.oRun the compiled sample to verify:
$ sudo ./samples/bpf/trace_output
recv 1766352 events per sec5. Extracting Key Steps of the eBPF Build Process
The make headers_install step generates a usr/include/ directory with ~931 files, of which 677 match the system’s /usr/include/ provided by the kernel-headers package, effectively reproducing the kernel‑headers content.
$ make headers_install
$ ls usr/include/ -R | wc -l
931
$ diff -rs usr/include/ /usr/include/ | grep '^Files' | wc -l
6776. Manual Step‑by‑Step Analysis
We break the compilation into steps A‑H, showing exact commands and the purpose of each flag.
# Step A1‑A4: Compile libbpf, bpf, btf, nlattr with -fPIC and include paths.
# Step B: ld -r to combine objects.
# Step C: ar rcs to create static libbpf.a.
# Step D‑F: Compile user‑space objects with -O2, -std=gnu89, and multiple -I include directories.
# Step G: Link final trace_output binary with libbpf.a, -lelf, -lrt.
# Step H: clang + llc to compile kernel‑space eBPF object.7. Exploring Kernel 4.9 Differences
On kernel 4.9 the final link command uses libbpf.o instead of the static library:
$ gcc -o samples/bpf/trace_output samples/bpf/bpf_load.o samples/bpf/libbpf.o samples/bpf/trace_output_user.o -lelf -lrt8. Further Exploration
This is the first article of the eBPF hands‑on series; the next part will investigate compiling eBPF programs completely independent of the kernel source.
9. Appendix: Full Command List for Manual Pure‑C eBPF Compilation
cd /tmp/
rm -fr /tmp/linux-4.18
tar -zxvf linux-4.18.tar.gz
cd /tmp/linux-4.18
make oldconfig && make init
make headers_install
cd tools/lib/bpf/
# A1‑A4
gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-4.18/tools/include -I/tmp/linux-4.18/tools/arch/x86/include/uapi -I/tmp/linux-4.18/tools/include/uapi -I/tmp/linux-4.18/tools/perf -D"BUILD_STR(s)=#s" -c -o libbpf.o libbpf.c
gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-4.18/tools/include -I/tmp/linux-4.18/tools/arch/x86/include/uapi -I/tmp/linux-4.18/tools/include/uapi -I/tmp/linux-4.18/tools/perf -D"BUILD_STR(s)=#s" -c -o bpf.o bpf.c
gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-4.18/tools/include -I/tmp/linux-4.18/tools/arch/x86/include/uapi -I/tmp/linux-4.18/tools/include/uapi -I/tmp/linux-4.18/tools/perf -D"BUILD_STR(s)=#s" -c -o btf.o btf.c
gcc -g -DHAVE_LIBELF_MMAP_SUPPORT -DCOMPAT_NEED_REALLOCARRAY -fPIC -I. -I/tmp/linux-4.18/tools/include -I/tmp/linux-4.18/tools/arch/x86/include/uapi -I/tmp/linux-4.18/tools/include/uapi -I/tmp/linux-4.18/tools/perf -D"BUILD_STR(s)=#s" -c -o nlattr.o nlattr.c
# B
ld -r -o libbpf-in.o libbpf.o bpf.o nlattr.o btf.o
# C
ar rcs libbpf.a libbpf-in.o
# D‑F
gcc -O2 -fomit-frame-pointer -std=gnu89 -I./usr/include -I./tools/lib/ -I./tools/testing/selftests/bpf/ -I./tools/lib/ -I./tools/include -I./tools/perf -I./usr/include -Wno-unused-variable -c -o samples/bpf/bpf_load.o samples/bpf/bpf_load.c
gcc -O2 -fomit-frame-pointer -std=gnu89 -I./usr/include -I./tools/lib/ -I./tools/testing/selftests/bpf/ -I./tools/lib/ -I./tools/include -I./tools/perf -I./tools/lib/bpf/ -c -o samples/bpf/trace_output_user.o samples/bpf/trace_output_user.c
gcc -O2 -fomit-frame-pointer -std=gnu89 -I./usr/include -I./tools/lib/ -I./tools/testing/selftests/bpf/ -I./tools/lib/ -I./tools/include -I./tools/perf -I./tools/lib/bpf/ -c -o samples/bpf/../../tools/testing/selftests/bpf/trace_helpers.o samples/bpf/../../tools/testing/selftests/bpf/trace_helpers.c
# G
gcc -o samples/bpf/trace_output samples/bpf/bpf_load.o samples/bpf/trace_output_user.o samples/bpf/../../tools/testing/selftests/bpf/trace_helpers.o /tmp/linux-4.18/samples/bpf/../../tools/lib/bpf/libbpf.a -lelf -lrt
# H
clang -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/8/include -I./arch/x86/include -I./arch/x86/include/generated -I./include -I./arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I./include/uapi -I./include/generated/uapi -include ./include/linux/kconfig.h -Isamples/bpf -I./tools/testing/selftests/bpf/ -D__KERNEL__ -D__BPF_TRACING__ -D__TARGET_ARCH_x86 -O2 -emit-llvm -c samples/bpf/trace_output_kern.c -o - | llc -march=bpf -filetype=obj -o samples/bpf/trace_output_kern.oSigned-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Alibaba Cloud Big Data AI Platform
The Alibaba Cloud Big Data AI Platform builds on Alibaba’s leading cloud infrastructure, big‑data and AI engineering capabilities, scenario algorithms, and extensive industry experience to offer enterprises and developers a one‑stop, cloud‑native big‑data and AI capability suite. It boosts AI development efficiency, enables large‑scale AI deployment across industries, and drives business value.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
