Skip to content

Commit 33873b5

Browse files
committed
docs: Add documentation for BPF targets
1 parent 39dc268 commit 33873b5

File tree

3 files changed

+166
-2
lines changed

3 files changed

+166
-2
lines changed

src/doc/rustc/src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
- [\*-unknown-fuchsia](platform-support/fuchsia.md)
5454
- [\*-unknown-trusty](platform-support/trusty.md)
5555
- [\*-kmc-solid_\*](platform-support/kmc-solid.md)
56+
- [bpf\*-unknown-none](platform-support/bpf-unknown-none.md)
5657
- [csky-unknown-linux-gnuabiv2\*](platform-support/csky-unknown-linux-gnuabiv2.md)
5758
- [hexagon-unknown-linux-musl](platform-support/hexagon-unknown-linux-musl.md)
5859
- [hexagon-unknown-none-elf](platform-support/hexagon-unknown-none-elf.md)

src/doc/rustc/src/platform-support.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,8 @@ target | std | host | notes
296296
[`armv7s-apple-ios`](platform-support/apple-ios.md) | ✓ | | Armv7-A Apple-A6 Apple iOS
297297
[`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * | | Bare Armv8-R, hardfloat
298298
`avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core`
299-
`bpfeb-unknown-none` | * | | BPF (big endian)
300-
`bpfel-unknown-none` | * | | BPF (little endian)
299+
[`bpfeb-unknown-none`](platform-support/bpf-unknown-none.md) | * | | BPF (big endian)
300+
[`bpfel-unknown-none`](platform-support/bpf-unknown-none.md) | * | | BPF (little endian)
301301
`csky-unknown-linux-gnuabiv2` | ✓ | | C-SKY abiv2 Linux (little endian)
302302
`csky-unknown-linux-gnuabiv2hf` | ✓ | | C-SKY abiv2 Linux, hardfloat (little endian)
303303
[`hexagon-unknown-linux-musl`](platform-support/hexagon-unknown-linux-musl.md) | ✓ | | Hexagon Linux with musl 1.2.3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# `bpf*-unknown-none`
2+
3+
**Tier: 3**
4+
5+
* `bpfeb-unknown-none` (big endian)
6+
* `bpfel-unknown-none` (little endian)
7+
8+
Targets for the 64-bit [BPF virtual machine][ebpf].
9+
10+
## Target maintainers
11+
12+
- [@alessandrod](https://github.com/alessandrod)
13+
- [@dave-tucker](https://github.com/dave-tucker)
14+
- [@tamird](https://github.com/tamird)
15+
- [@vadorovsky](https://github.com/vadorovsky)
16+
17+
## Requirements
18+
19+
BPF targets require a Rust toolchain with the `rust-src` component. In
20+
addition, you must install the [bpf-linker].
21+
22+
They don't support std and alloc and are meant for a `no_std` environment.
23+
24+
`extern "C"` uses the [BPF ABI calling convention][bpf-abi].
25+
26+
Produced binaries use the ELF format.
27+
28+
## Building the target
29+
30+
You can build Rust with support for BPF targets by adding them to the `target`
31+
list in `config.toml`:
32+
33+
```toml
34+
[build]
35+
target = ["bpfeb-unknown-none", "bpfel-unknown-none"]
36+
```
37+
38+
## Building Rust programs
39+
40+
Rust does not yet ship pre-compiled artifacts for this target. To compile for
41+
this target, you will either need to build Rust with the target enabled (see
42+
"Building the target" above), or build your own copy of `core` by using
43+
`build-std` or similar.
44+
45+
Building the BPF target requires specifying it explicitly. Users can either
46+
add it to the `target` list in `config.toml`:
47+
48+
```toml
49+
[build]
50+
target = ["bpfel-unknown-none"]
51+
```
52+
53+
Or specify it directly in the `cargo build` invocation:
54+
55+
```console
56+
cargo +nightly build -Z build-std=core --target bpfel-unknown-none
57+
```
58+
59+
BPF has its own debug info format called [BTF][btf].
60+
61+
BPF targets use [bpf-linker], an LLVM bitcode linker, which by
62+
default strips the debug info, but it has an experimental feature of emitting
63+
BTF, which can be enabled by adding `-C link-arg=--btf` to `RUSTFLAGS`. With
64+
that feature enabled, [bpf-linker] does not only link different
65+
crates/modules, but also performs a necessary sanitization of debug info, which
66+
is required to produce valid [BTF][btf] acceptable by the Linux kernel.
67+
68+
## Error handling
69+
70+
There is no concept of stack unwinding in BPF, therefore BPF programs are
71+
expected to handle errors in a recoverable manner. Therefore most BPF programs
72+
written in Rust use the following no-op panic handler implementation:
73+
74+
```rust,ignore
75+
#[cfg(not(test))]
76+
#[panic_handler]
77+
fn panic(_info: &core::panic::PanicInfo) -> ! {
78+
loop {}
79+
}
80+
```
81+
82+
Infinite loops are forbidden by the BPF verifier. Therefore, if the program
83+
contains any code which can panic, the BPF VM refuses to load it.
84+
85+
## Testing
86+
87+
BPF bytecode needs to be executed on a BPF virtual machine, like the one
88+
provided by the Linux kernel or one of the user-space implementations like
89+
[rbpf][rbpf]. None of them support running Rust testsuite. One of the reasons
90+
is the lack of support for panicking.
91+
92+
Therefore, unit tests need to run on the host system. That requirement can be
93+
enforced by the following conditional check:
94+
95+
```rust,ignore
96+
#[cfg(all(not(target_arch = "bpf"), test))]
97+
mod test {}
98+
```
99+
100+
## Cross-compilation toolchains
101+
102+
BPF programs are always cross-compiled from a host (e.g.
103+
`x86_64-unknown-linux-*`) for a BPF target (e.g. `bpfel-unknown-none`).
104+
105+
The endianness of a chosen BPF target needs to match the endianness of the BPF
106+
VM host on which the program is supposed to run.
107+
108+
The architecture of the BPF VM host often has an impact on types that the BPF
109+
programs should use. For example [kprobes][kprobe], [fprobes][fprobe] and
110+
[uprobes][uprobe] allow dynamic function tracing and lookup into host registers
111+
through the [`pt_regs`][pt-regs] struct, which differs across architectures.
112+
113+
That difference is still not a concern of the compiler. Instead, it should be
114+
handled by the developers. [Aya][aya] (the library for writing Linux BPF
115+
programs and the main consumer of BPF targets in Rust) handles that by
116+
providing the [`aya-ebpf-cty`][aya-ebpf-cty] crate, with type aliases similar
117+
to those provided by [`core:ffi`][core-ffi]. [`aya-ebpf-cty`][aya-ebpf-cty]
118+
allows to specify the VM target through the `CARGO_CFG_BPF_TARGET_ARCH`
119+
environment variable (e.g. `CARGO_CFG_BPF_TARGET_ARCH=aarch64`).
120+
121+
## C code
122+
123+
It's possible to link a Rust BPF project to bitcode or object files which are
124+
built from C code with [clang][clang]. It can be done using a `rustc-link-lib`
125+
instruction in `build.rs`. Example:
126+
127+
```rust
128+
use std::{env, process::Command};
129+
130+
let out_dir = env::var("OUT_DIR").unwrap();
131+
let c_module = "my_module.bpf.c";
132+
let s = Command::new("clang")
133+
.arg("-I")
134+
.arg("src/")
135+
.arg("-O2")
136+
.arg("-emit-llvm")
137+
.arg("-target")
138+
.arg("bpf")
139+
.arg("-c")
140+
.arg("-g")
141+
.arg(c_module)
142+
.arg("-o")
143+
.arg(format!("{out_dir}/my_module.bpf.o"))
144+
.status()
145+
.unwrap();
146+
assert!(s.success());
147+
println!("cargo:rustc-link-search=native={out_dir}");
148+
println!("cargo:rustc-link-lib=link-arg={out_dir}/my_module.bpf.o");
149+
```
150+
151+
[ebpf]: https://ebpf.io/
152+
[bpf-linker]: https://github.com/aya-rs/bpf-linker
153+
[bpf-abi]: https://www.kernel.org/doc/html/v6.13-rc5/bpf/standardization/abi.html
154+
[btf]: https://www.kernel.org/doc/html/latest/bpf/btf.html
155+
[rbpf]: https://github.com/qmonnet/rbpf
156+
[kprobe]: https://www.kernel.org/doc/html/latest/trace/kprobes.html
157+
[fprobe]: https://www.kernel.org/doc/html/latest/trace/fprobe.html
158+
[uprobe]: https://www.kernel.org/doc/html/latest/trace/uprobetracer.html
159+
[pt-regs]: https://elixir.bootlin.com/linux/v6.12.6/source/arch/x86/include/uapi/asm/ptrace.h#L44
160+
[aya]: https://aya-rs.dev
161+
[aya-ebpf-cty]: https://github.com/aya-rs/aya/tree/main/ebpf/aya-ebpf-cty
162+
[core-ffi]: https://doc.rust-lang.org/stable/core/ffi/index.html
163+
[clang]: https://clang.llvm.org/

0 commit comments

Comments
 (0)