Section Naming
You may have seen the SEC()
macro used around eBPF C code. This macro sends
a hint to the compiler to place a symbol (a variable or function) in a specific
section of the resulting eBPF object binary.
Typically, program binaries for Unix-like systems are divided into so-called
'sections'. All sections have names, many of which are assigned special meaning.
For example, .text
is where program
text (executable instructions) goes
by default.
Like common application binaries, eBPF also relies heavily on section naming to distinguish various parts of an application. As an example, the section name of an individual eBPF program determines its program type, affecting the way the program is verified by the kernel and defining what the program is allowed to do.
Executable Linkable Format (ELF)¶
Executable Linkable Format (ELF) is the standard application binary format for Linux. It is also used as the output format of LLVM's BPF backend. ELF binaries are typically executed directly by the kernel, but for eBPF, a different approach is needed.
eBPF programs are not executable in the traditional sense. They depend on a user
space component that loads them, manages their resources, and can interact with
their components. This is where projects such as libbpf and ebpf-go
come
in.
For compatibility reasons, ebpf-go
follows the section naming conventions
established by libbpf, since we consider upstream decisions to be authoritative
on this subject. There's also little reason to do things differently; section
names are essentially considered an API.
How do I explore an ELF's contents?
You can display an ELF's section table using readelf -S <binary>
.
For visualizing a program instructions or the contents of a map's data
section, you'll need a tool from the LLVM toolchain: llvm-objdump
. For
example: llvm-objdump -SD my_ebpf.o -j xdp
. This will limit output to
the xdp
section (see Program Sections), display
corresponding source code lines if available using -S
, and display
disassembled instructions using -D
. The same can be done for data sections
like .data
and .rodata.
(see Map Sections).
Also worth mentioning: display an eBPF object's BTF type information using
bpftool btf dump file my_object.o
.
Section Prefixes¶
To support encoding extra information into section names, a prefix convention
using forward slashes /
is used. For example, a Kprobe-type program meant to
be attached to the slub_flush
kernel symbol would be put into an ELF section
called kprobe/slub_flush
.
Miscellaneous Sections¶
license
-
In order to use certain BPF helpers in your program, it must be licensed under a GPL-compatible license. BPF programs licensing follows the same rules as kernel module licensing. This is explained in more detail in the Linux kernel's BPF licensing documentation. See the
license_is_gpl_compatible
function in the Linux source code or the Module Licensing table.This section must only contain the license string of the programs in the ELF. for example:
char __license[] SEC("license") = "Dual MIT/GPL";
. version
-
Deprecated. Kernels <5.0 require this section to contain a value matching the kernel's
LINUX_VERSION_CODE
for Kprobe-type programs. Always omit this,ebpf-go
will populate this field automatically if needed.
Map Sections¶
.maps
-
This section is dedicated to BTF-style Map definitions.
maps
-
Deprecated. This section is expected to only contain fixed-width
struct bpf_map_def
variables. Larger structs like iproute2'sstruct bpf_elf_map
can also be used for backwards compatibility. Any extra bytes past the end of the size of astruct bpf_map_def
are exposed byMapSpec.Extra
and must be drained before attempting to create the Map.
Advanced: Special Map Sections¶
.data*
-
The LLVM BPF backend implements accesses to mutable global variables as direct Array Map accesses. Since a single BPF program can be executed concurrently as a result of the kernel processing packets and other events asynchronously, a data section and the global variables it represents are considered shared memory.
Variables can be emitted to specific sections, like
SEC(".data.foo") my_var = 123;
, as long as they match the.data*
prefix. This can prove useful for isolating certain variables to well-known sections for Go code generation or custom variable rewriting logic.Global, non-hidden variables are emitted to
CollectionSpec.Variables
, where they can be modified before loading the CollectionSpec into the kernel. See Global Variables for instructions. .rodata*
-
Like
.data*
, but for constants. These become read-only after loading the CollectionSpec into the kernel, and are also exposed throughCollectionSpec.Variables
. .bss
-
Section emitted by the compiler when zero-initialized globals are present in the ELF. Is typically zero-length in the ELF, and initialized by
ebpf-go
after loading. Also exposed throughCollectionSpec.Variables
. .rel*
-
Not exposed by
ebpf-go
, only used behind the scenes. Relocation sections contain relocation records against their non-.rel
prefixed counterparts. This is mainly used for fixing up BPF instructions referring to Maps and global variables.
Program Sections¶
Names of Program sections mainly define the program's ProgramType
, but also its AttachType
and AttachFlags
are
automatically set for convenience based on its section name.
As described previously, section prefixes containing a forward slash /
expect
a second component to follow the slash. For example, a program in the
kprobe/slub_flush
section will automatically have its ProgramSpec.AttachTo
field set to slub_flush
to facilitate
attaching the program later on.
Additionally, the program's original full section name can be found in ProgramSpec.SectionName
.
There's also upstream libbpf
documentation for
this. Not all of libbpf's program types may be supported by ebpf-go
yet.
If a program type you require is missing, please file an issue or send a
pull request!
Section (Prefix) | ProgramType |
AttachType |
AttachFlags |
---|---|---|---|
socket | SocketFilter | ||
sk_reuseport/migrate | SkReuseport | AttachSkReuseportSelectOrMigrate | |
sk_reuseport | SkReuseport | AttachSkReuseportSelect | |
kprobe/ | Kprobe | ||
uprobe/ | Kprobe | ||
kretprobe/ | Kprobe | ||
uretprobe/ | Kprobe | ||
tc | SchedCLS | ||
classifier | SchedCLS | ||
action | SchedACT | ||
tracepoint/ | TracePoint | ||
tp/ | TracePoint | ||
raw_tracepoint/ | RawTracepoint | ||
raw_tp/ | RawTracepoint | ||
raw_tracepoint.w/ | RawTracepointWritable | ||
raw_tp.w/ | RawTracepointWritable | ||
tp_btf/ | Tracing | AttachTraceRawTp | |
fentry/ | Tracing | AttachTraceFEntry | |
fmod_ret/ | Tracing | AttachModifyReturn | |
fexit/ | Tracing | AttachTraceFExit | |
fentry.s/ | Tracing | AttachTraceFEntry | BPF_F_SLEEPABLE |
fmod_ret.s/ | Tracing | AttachModifyReturn | BPF_F_SLEEPABLE |
fexit.s/ | Tracing | AttachTraceFExit | BPF_F_SLEEPABLE |
freplace/ | Extension | ||
lsm/ | LSM | AttachLSMMac | |
lsm.s/ | LSM | AttachLSMMac | BPF_F_SLEEPABLE |
iter/ | Tracing | AttachTraceIter | |
iter.s/ | Tracing | AttachTraceIter | BPF_F_SLEEPABLE |
syscall | Syscall | ||
xdp.frags_devmap/ | XDP | AttachXDPDevMap | BPF_F_XDP_HAS_FRAGS |
xdp_devmap/ | XDP | AttachXDPDevMap | |
xdp.frags_cpumap/ | XDP | AttachXDPCPUMap | BPF_F_XDP_HAS_FRAGS |
xdp_cpumap/ | XDP | AttachXDPCPUMap | |
xdp.frags | XDP | BPF_F_XDP_HAS_FRAGS | |
xdp | XDP | ||
perf_event | PerfEvent | ||
lwt_in | LWTIn | ||
lwt_out | LWTOut | ||
lwt_xmit | LWTXmit | ||
lwt_seg6local | LWTSeg6Local | ||
cgroup_skb/ingress | CGroupSKB | AttachCGroupInetIngress | |
cgroup_skb/egress | CGroupSKB | AttachCGroupInetEgress | |
cgroup/skb | CGroupSKB | ||
cgroup/sock_create | CGroupSock | AttachCGroupInetSockCreate | |
cgroup/sock_release | CGroupSock | AttachCgroupInetSockRelease | |
cgroup/sock | CGroupSock | AttachCGroupInetSockCreate | |
cgroup/post_bind4 | CGroupSock | AttachCGroupInet4PostBind | |
cgroup/post_bind6 | CGroupSock | AttachCGroupInet6PostBind | |
cgroup/dev | CGroupDevice | AttachCGroupDevice | |
sockops | SockOps | AttachCGroupSockOps | |
sk_skb/stream_parser | SkSKB | AttachSkSKBStreamParser | |
sk_skb/stream_verdict | SkSKB | AttachSkSKBStreamVerdict | |
sk_skb | SkSKB | ||
sk_msg | SkMsg | AttachSkMsgVerdict | |
lirc_mode2 | LircMode2 | AttachLircMode2 | |
flow_dissector | FlowDissector | AttachFlowDissector | |
cgroup/bind4 | CGroupSockAddr | AttachCGroupInet4Bind | |
cgroup/bind6 | CGroupSockAddr | AttachCGroupInet6Bind | |
cgroup/connect4 | CGroupSockAddr | AttachCGroupInet4Connect | |
cgroup/connect6 | CGroupSockAddr | AttachCGroupInet6Connect | |
cgroup/sendmsg4 | CGroupSockAddr | AttachCGroupUDP4Sendmsg | |
cgroup/sendmsg6 | CGroupSockAddr | AttachCGroupUDP6Sendmsg | |
cgroup/recvmsg4 | CGroupSockAddr | AttachCGroupUDP4Recvmsg | |
cgroup/recvmsg6 | CGroupSockAddr | AttachCGroupUDP6Recvmsg | |
cgroup/getpeername4 | CGroupSockAddr | AttachCgroupInet4GetPeername | |
cgroup/getpeername6 | CGroupSockAddr | AttachCgroupInet6GetPeername | |
cgroup/getsockname4 | CGroupSockAddr | AttachCgroupInet4GetSockname | |
cgroup/getsockname6 | CGroupSockAddr | AttachCgroupInet6GetSockname | |
cgroup/sysctl | CGroupSysctl | AttachCGroupSysctl | |
cgroup/getsockopt | CGroupSockopt | AttachCGroupGetsockopt | |
cgroup/setsockopt | CGroupSockopt | AttachCGroupSetsockopt | |
struct_ops+ | StructOps | ||
sk_lookup/ | SkLookup | AttachSkLookup | |
seccomp | SocketFilter | ||
kprobe.multi | Kprobe | AttachTraceKprobeMulti | |
kretprobe.multi | Kprobe | AttachTraceKprobeMulti |
Authored by