Skip to content

Commit 8da8a10

Browse files
committed
docs: Add documentation for BPF targets
1 parent 7349f6b commit 8da8a10

File tree

2 files changed

+125
-2
lines changed

2 files changed

+125
-2
lines changed

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

Lines changed: 2 additions & 2 deletions
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
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
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 [eBPF virtual machine][ebpf].
9+
10+
## Target maintainers
11+
12+
- [@dave-tucker](https://github.com/dave-tucker)
13+
- [@vadorovsky](https://github.com/vadorovsky)
14+
15+
## Requirements
16+
17+
BPF targets require a Rust toolchain with `rust-src` component and
18+
[bpf-linker][bpf-linker].
19+
20+
They don't support std and alloc and are meant for `no_std` environment.
21+
22+
`extern "C"` uses the [BPF ABI calling convention][bpf-abi].
23+
24+
Produced binaries use the ELF format.
25+
26+
## Building the target
27+
28+
You can build Rust with support for BPF targets by adding them to the `target`
29+
list in `config.toml`:
30+
31+
```toml
32+
[build]
33+
target = ["bpfeb-unknown-none", "bpfel-unknown-none"]
34+
```
35+
36+
## Building Rust programs
37+
38+
Rust does not yet ship pre-compiled artifacts for this target. To compile for
39+
this target, you will either need to build Rust with the target enabled (see
40+
"Building the target" above), or build your own copy of `core` by using
41+
`build-std` or similar.
42+
43+
Building the BPF target requires specifying it explicitly. Users can either
44+
add them to the `target` list in `config.toml`:
45+
46+
```toml
47+
[build]
48+
target = ["bpfel-unknown-none"]
49+
```
50+
51+
Or specify it directly in the `cargo build` invocation:
52+
53+
```console
54+
cargo +nightly build -Z build-std=core --target bpfel-unknown-none
55+
```
56+
57+
## Testing
58+
59+
eBPF bytecode need to be executed on an eBPF virtual machine, like the one
60+
provided by the Linux kernel or one of user-space implementations like
61+
[rbpf][rbpf]. None of them supports running Rust testsuite.
62+
63+
Currently the best way of unit testing the code used in BPF programs is
64+
extracting it to a separate crate, which can be built and ran on a host target,
65+
and using it as a dependency.
66+
67+
## Cross-compilation toolchains
68+
69+
Technically speaking, every build for BPF target is a cross build and is
70+
performed on a host target (e.g. `x86_64-unknown-linux-*`) for the BPF target
71+
(e.g. `bpfel-unknown-none`). The resulting BPF bytecode can be executed on a
72+
virtual machine, which can run on different host architectures (x86_64, aarch64,
73+
riscv64 etc.). The BPF bytecode format stays the same regardless of the host
74+
architecture hosting the virtual machine. When building BPF code, compiler does
75+
not care about the architecture hosting the VM.
76+
77+
That said, in the context of BPF VM in the Linux kernel and BPF programs
78+
interacting with kernel types, the architecture which hosts the VM affects
79+
these types. For example, `char` in C translates to different Rust types
80+
on different architectures (`i8` on x86_64, `u8` on aarch64). Therefore, kernel
81+
types are different across architectures. Solving that problem is still not a
82+
concern of the Rust compiler itself. On the other hand, [Aya][aya] (the library
83+
for writing BPF programs and the main consumer of BPF targets in Rust) handles
84+
the C type differences by providing the [`aya-ebpf-cty`][aya-ebpf-cty] library,
85+
with type aliases similar to those provided by `core:ffi`. aya-ebpf-cty allows
86+
to specify the VM host target through the `CARGO_CFG_BPF_TARGET_ARCH`
87+
environment variable (e.g. `CARGO_CFG_BPF_TARGET_ARCH=aarch64`).
88+
89+
## C code
90+
91+
It's possible to link a Rust BPF project to bitcode or object files which are
92+
built from C code with [clang][clang]. It can be done using `rustc-link-lib`
93+
instruction in `build.rs`. Example:
94+
95+
```rust
96+
let out_dir = std::env::var("OUT_DIR").unwrap();
97+
let c_module = "my_module.bpf.c"
98+
let s = Command::new("clang")
99+
.arg("-I")
100+
.arg("src/")
101+
.arg("-O2")
102+
.arg("-emit-llvm")
103+
.arg("-target")
104+
.arg("bpf")
105+
.arg("-c")
106+
.arg("-g")
107+
.arg(c_module)
108+
.arg("-o")
109+
.arg(format!("{out_dir}/my_module.bpf.o"))
110+
.status()
111+
.unwrap();
112+
assert!(s.success());
113+
println!("cargo:rustc-link-search=native={out_dir}");
114+
println!("cargo:rustc-link-lib=link-arg={out_dir}/my_module.bpf.o");
115+
```
116+
117+
[ebpf]: https://ebpf.io/
118+
[bpf-linker]: https://github.com/aya-rs/bpf-linker
119+
[bpf-abi]: https://www.kernel.org/doc/html/v6.13-rc5/bpf/standardization/abi.html
120+
[rbpf]: https://github.com/qmonnet/rbpf
121+
[aya]: https://aya-rs.dev
122+
[aya-ebpf-cty]: https://github.com/aya-rs/aya/tree/main/ebpf/aya-ebpf-cty
123+
[clang]: https://clang.llvm.org/

0 commit comments

Comments
 (0)