-
Notifications
You must be signed in to change notification settings - Fork 0
Cross compiling eBPF Programs
There are several ways of building eBPF applications for Linux. The main and most straightforward way consists of these steps:
- Build the eBPF part using Clang (it's a regular Object in ELF format).
- Generate a special C file named "skeleton" which contains an entire blob
for the eBPF part and the functions for loading it using
libbpf. - Write a C program which uses these functions for opening the eBPF application, loading it into the kernel and attaching it to events.
- Build your C program using GCC toolchain and run on your target.
Consider the minimal program from libbpf-bootstrap
repository. It consists of
2 files:
minimal.c and minimal.bpf.c. Ensure that libbpf and the
corresponding development files are installed (e.g., for Fedora you need to
install libbpf and libbpf-devel packages). Also, a recent version of
bpftool utility must be installed. Then you can build the program using
these commands:
# Replace -D__TARGET_ARCH_x86 to an appropriate one for your platform
clang -g \
-O2 \
-Wall \
-target bpf \
-D__TARGET_ARCH_x86 \
-c minimal.bpf.c \
-o minimal.bpf.o
bpftool gen skeleton minimal.bpf.o > minimal.skel.h
gcc minimal.c -lbpf \
-lelf \
-lz \
-o minimalThen you can run this program with root privileges:
# The 2 commands below are a one-time setup. Run them with root privileges.
mount -t debugfs debugfs /sys/kernel/debug
sysctl net.core.bpf_jit_enable=1 # Keep 0, if you don't want JIT.
$ sudo ./minimal
[sudo] password for user:
libbpf: loading object 'minimal_bpf' from buffer
libbpf: elf: section(3) tp/syscalls/sys_enter_write, size 104, link 0, flags 6, type=1
libbpf: sec 'tp/syscalls/sys_enter_write': found program 'handle_tp' at insn offset 0 (0 bytes), code size 13 insns (104 bytes)
libbpf: elf: section(4) .reltp/syscalls/sys_enter_write, size 32, link 22, flags 40, type=9
libbpf: elf: section(5) license, size 13, link 0, flags 3, type=1
libbpf: license of minimal_bpf is Dual BSD/GPL
libbpf: elf: section(6) .bss, size 4, link 0, flags 3, type=8
libbpf: elf: section(7) .rodata, size 28, link 0, flags 2, type=1
libbpf: elf: section(13) .BTF, size 609, link 0, flags 0, type=1
libbpf: elf: section(15) .BTF.ext, size 160, link 0, flags 0, type=1
libbpf: elf: section(22) .symtab, size 336, link 1, flags 0, type=2
libbpf: looking for externs among 14 symbols...
libbpf: collected 0 externs total
libbpf: map 'minimal_.bss' (global data): at sec_idx 6, offset 0, flags 400.
libbpf: map 0 is "minimal_.bss"
libbpf: map 'minimal_.rodata' (global data): at sec_idx 7, offset 0, flags 480.
libbpf: map 1 is "minimal_.rodata"
libbpf: sec '.reltp/syscalls/sys_enter_write': collecting relocation for section(3) 'tp/syscalls/sys_enter_write'
libbpf: sec '.reltp/syscalls/sys_enter_write': relo #0: insn #2 against 'my_pid'
libbpf: prog 'handle_tp': found data map 0 (minimal_.bss, sec 6, off 0) for insn 2
libbpf: sec '.reltp/syscalls/sys_enter_write': relo #1: insn #6 against '.rodata'
libbpf: prog 'handle_tp': found data map 1 (minimal_.rodata, sec 7, off 0) for insn 6
libbpf: map 'minimal_.bss': created successfully, fd=4
libbpf: map 'minimal_.rodata': created successfully, fd=5
Successfully started! Please run `sudo cat /sys/kernel/debug/tracing/trace_pipe` to see output of the BPF programs.Some examples from libbpf-bootstrap use vmlinux.h - It's a header file
with the definitions of all the data structures for that particular kernel. The
easiest way to obtain it on the host system is by using bpftool, if the
kernel was built with CONFIG_DEBUG_INFO_BTF=y:
bpftool --debug btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.hElse, you can generate vmlinux.h from any vmlinux image with BTF
information:
bpftool --debug btf dump file path/to/your/vmlinux format c > vmlinux.hSuppose that the root directory of the toolchain for ARC HS 4x is
/tools/arc-linux-gnu. /tools/arc-linux-gnu/bin must be in PATH
variable. bpftool must be available too.
Create a directory for ARC's libraries and includes:
mkdir /tools/sysrootExport common variables:
export CFLAGS="-Og -g3 -fPIC"
export CXXFLAGS="-Og -g3 -fPIC"
export CPPFLAGS="-I/tools/sysroot/include"
export LDFLAGS="-L/tools/sysroot/lib"We are going to use the latest releases of libraries at the moment of writing of this manual instead of development branches.
git clone -b v1.2.13 https://github.com/madler/zlib
cd zlib
./configure CHOST="arc-linux-gnu" --static --prefix="/tools/sysroot"
make installgit clone -b elfutils-0.189 https://sourceware.org/git/elfutils.git
cd elfutils
autoreconf -i -f
./configure --host=arc-linux-gnu \
--target=arc-linux-gnu \
--disable-dependency-tracking \
--disable-nls \
--program-prefix="eu-" \
--disable-libdebuginfod \
--disable-debuginfod \
--without-bzlib \
--without-lzma \
--without-zstd \
--prefix="/tools/sysroot" \
--enable-maintainer-mode
make -C libelf install-includeHEADERS install-libLIBRARIESgit clone -b v1.1.0 https://github.com/libbpf/libbpf
cd libbpf/src
make BUILD_STATIC_ONLY="y" \
PREFIX="/" \
DESTDIR="/tools/sysroot" \
CROSS_COMPILE="arc-linux-gnu-" \
install install_uapi_headersMake sure that you have a recent version of bpftool (≥7).
bpftool --debug btf dump file path/to/your/vmlinux format c > /tools/sysroot/include/vmlinux.hAfter building and installing all libraries /tools/sysroot should look like this:
$ tree -L 3 /tools/sysroot
/tools/sysroot
|-- include
| |-- bpf
| | |-- bpf_core_read.h
| | |-- bpf_endian.h
| | |-- bpf.h
| | |-- bpf_helper_defs.h
| | |-- bpf_helpers.h
| | |-- bpf_tracing.h
| | |-- btf.h
| | |-- libbpf_common.h
| | |-- libbpf.h
| | |-- libbpf_legacy.h
| | |-- libbpf_version.h
| | |-- skel_internal.h
| | `-- usdt.bpf.h
| |-- gelf.h
| |-- libelf.h
| |-- linux
| | |-- bpf.h
| | |-- bpf_common.h
| | `-- btf.h
| |-- nlist.h
| |-- zconf.h
| `-- zlib.h
|-- lib
| |-- libbpf.a
| |-- libelf.a
| |-- libz.a
| `-- pkgconfig
| |-- libbpf.pc
| `-- zlib.pc
`-- share
`-- man
`-- man3
9 directories, 26 files
# The paths where the native ARC tools and the cross ARC toolchain are installed
readonly NATIVE_SYSROOT=/tools/sysroot
readonly TOOLCHAIN_SYSROOT=/tools/arc-linux-gnu/sysroot
# Clang uses host's Linux headers if we don't pass toolchain's includes.
# Also, the -XClang arguments below are optional.
clang -g \
-O2 \
-Wall \
-target bpf \
-D__TARGET_ARCH_arc \
-I${NATIVE_SYSROOT}/usr/include \
-I${TOOLCHAIN_SYSROOT}/usr/include \
-Xclang -target-feature \
-Xclang +alu32 \
-c minimal.bpf.c \
-o minimal.bpf.o
# bpftool must be a recent version (≥7)
bpftool gen skeleton minimal.bpf.o > minimal.skel.h
# shared library build (-latomic is listed for future reference)
arc-linux-gcc minimal.c \
-I${NATIVE_SYSROOT}/usr/include \
-L${NATIVE_SYSROOT}/usr/lib \
-lbpf \
-lelf \
-lz \
-latomic \
-o minimal
# static build (-latomic is listed for future reference)
arc-linux-gcc minimal.c \
-I${SYSROOT}/usr/include \
${NATIVE_SYSROOT}/usr/lib/libbpf.a \
${NATIVE_SYSROOT}/usr/lib/libelf.a \
${NATIVE_SYSROOT}/usr/lib/libz.a \
-latomic \
-o minimalYou can use a testbench which automates all the above steps for building eBPF programs for ARC: