Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

CO-RE support in Rust and Aya

CO-RE spans the build and load stages. Compilers preserve the type and field information needed for relocation, and the build produces an eBPF object containing CO-RE records. At load time, Aya uses those records and the target kernel’s BTF to adapt the program.

ComponentResponsibilityStatus
Rust compilerDescribe relocatable kernel accesses in Rust eBPF code.In development.
bpf-linkerLink LLVM bitcode and emit an eBPF object.BTF emission supported; CO-RE emission requires metadata from the compiler.
Aya loaderApply CO-RE relocation records to an eBPF object.Supported.

This means Aya can already load CO-RE programs compiled from C. To use CO-RE from a Rust eBPF program today, you can put the kernel field accesses in C shims and keep the rest of the program in Rust.

The status above was checked on October 19, 2026. Follow the linked upstream work for updates.

Rust’s compiler

BTF output for Rust eBPF programs is already available through bpf-linker. Native Rust support for producing CO-RE relocations is still in development. For details of the proposed language support and design discussions, see the pre-RFC discussion on Rust Internals and RFC #3966. Implementation progress is tracked in issue #160616. The proposed APIs are still evolving.

BTF describes types and their layouts. CO-RE relocation records additionally connect specific instructions to the types and fields they query. The Rust compiler work linked above focuses on generating the information needed for these records. Enabling BTF output alone does not create them for ordinary Rust field accesses.

Ordinary Rust field accesses use the type layout determined at compile time. For example, suppose pid is at byte offset 16 in the Rust definition of task_struct. An access such as (*task).pid can compile to a read from task + 16. The instruction contains the offset, but does not identify the field as task_struct.pid.

If pid is at byte offset 24 on the target kernel, a CO-RE relocation record tells Aya’s loader which instruction accesses that field, allowing it to change the offset from 16 to 24. Without this record, the access still uses offset 16.

bpf-linker

bpf-linker links and optimizes LLVM bitcode produced by the Rust compiler, then uses LLVM’s BPF backend to emit an eBPF ELF object. A Rust eBPF build follows this flow:

flowchart TB
    accTitle: Rust eBPF build
    accDescr: Compile Rust to bitcode; bpf-linker emits an eBPF object.
    rust["Rust eBPF code"]
    rustc["rustc<br/>LLVM bitcode"]
    subgraph linker["bpf-linker"]
        link["Link and optimize"]
        backend["LLVM BPF backend"]
        link --> backend
    end
    object["eBPF ELF object"]
    rust --> rustc
    rustc --> linker
    linker --> object

With debug information and --btf enabled, bpf-linker also emits BTF. Before emission, it adjusts Rust debug information for kernel BTF compatibility. For example, kernels that require C-style BTF type names would reject Rust names such as Foo<u8>, so bpf-linker rewrites them. See the upstream discussion for details of these fixes.

The same --btf option enables CO-RE relocation emission, but this depends on the compiler preserving the required type and field access information.

Because it links LLVM bitcode, the LLVM version used by bpf-linker must match the one used by the Rust compiler. See its LLVM requirements when choosing a toolchain.

Aya’s loader

Aya’s userspace loader implements CO-RE relocations. It uses the type information and relocation records in an eBPF object together with the target kernel’s BTF to adjust the program before submitting it to the kernel. This works with CO-RE objects produced by Clang, including objects containing both Rust and C code, without a runtime dependency on libbpf.

By default, Aya reads the target BTF from /sys/kernel/btf/vmlinux when it is needed. You can also supply BTF explicitly through EbpfLoader::btf. That BTF must describe the kernel on which the program will run. For the supported relocation kinds, see Aya’s relocation implementation.

flowchart TD
    accTitle: CO-RE field offset relocation
    accDescr: Aya uses field records and target BTF to patch an offset.
    source["Build-time layout<br/>task_struct.pid at +16"]
    object["eBPF object<br/>Read task + 16<br/>CO-RE: task_struct.pid"]
    target["Target kernel BTF<br/>task_struct.pid at +24"]
    aya["Aya loader<br/>Resolve field offset"]
    patched["Patched read: task + 24"]
    source -->|Compiler records field identity| object
    object --> aya
    target --> aya
    aya --> patched

CO-RE can also resolve field sizes, signedness, bitfield shifts, type sizes, BTF type IDs and enum values. It can test whether fields, types and enum values exist, allowing programs to choose explicit fallbacks. See the CO-RE relocation kinds for details.

Note

Aya’s loader supports kernel symbol resolution (__ksym externs, including kfunc calls). It does not yet support struct_ops registration. These capabilities are separate from CO-RE relocations and have their own kernel requirements.