RFC: Support fully static libbpf-tools builds for Android/AArch64 deployment
Summary
BCC's libbpf-tools currently links libbpf statically, but normally leaves
system libraries such as libc, libelf, and zlib dynamically linked. This works
well on conventional Linux distributions, but it is not directly suitable for
Android devices, where the expected GNU/Linux shared libraries are generally
unavailable or incompatible.
This RFC proposes an optional AArch64 cross-build environment that builds the
required user-space libraries from source and produces fully static
libbpf-tools executables for deployment on Android devices.
The proposal is limited to the build and deployment workflow. It does not require changes to the functional source code of individual libbpf tools or their BPF programs.
Motivation
Android devices do not normally provide compatible versions of libraries such
as libelf.so.1, libz.so, or other GNU/Linux user-space dependencies needed
by dynamically linked libbpf-tools binaries. Packaging those shared
libraries with every tool also requires target-side library-path management
and introduces additional compatibility problems.
Fully static executables avoid those runtime shared-library dependencies. A
tool can be copied to the device with adb push and executed directly,
subject to the device's kernel configuration, BTF availability, SELinux
policy, and privileges.
Proposed build support
The proposed build environment would:
- use an AArch64 GNU/Linux cross compiler;
- build all required user-space dependencies from pinned source revisions;
- link libc, libelf, zlib, libzstd, liblzma, and libbpf statically as needed;
- preserve the existing native and partially static build as the default;
- provide an explicit, opt-in target or build script for fully static tools;
- use
-j3for all compilation stages; - audit generated ELF files to ensure that they contain no dynamic section,
interpreter, or
DT_NEEDEDentries; and - optionally stage the binaries for deployment with
adb push.
The intended interface could be a dedicated make target or a wrapper script, for example:
./scripts/build-static-aarch64.sh -j3The exact interface can be adjusted to match BCC project conventions.
Source-code impact
The prototype does not require modifications to the C source code of existing
libbpf-tools or to their BPF programs. Cross-build-specific behavior is kept
in external build scripts, Makefile options, dependency configuration, ELF
auditing, and deployment helpers.
The normal build remains unchanged. Fully static AArch64 output is enabled only when explicitly requested.
All required libraries are built from source. In particular, libelf.a is
linked into the resulting executables, so the Android device does not need
libelf.so.1.
Prototype and Android validation
The approach has been prototyped successfully. Multiple AArch64
libbpf-tools, including biosnoop, capable, and execsnoop, were built as
fully static executables and tested on an Android AArch64 device through
adb shell.
Example deployment:
adb push biosnoop /data/local/tmp/biosnoop
adb shell chmod 755 /data/local/tmp/biosnoop
adb shell /data/local/tmp/biosnoop
TIME(s) COMM PID DISK T SECTOR BYTES LAT(ms)
0.000000 POSIX timer 0 1206 sda WS 115717800 4096 0.153
0.000237 POSIX timer 0 1206 sda WS 144686432 4096 0.024
0.055405 kworker/0:3 1667 sda N -1 0 0.408
0.255093 dbthread 8623 sda WS 115718616 4096 0.130
0.255182 dbthread 8623 sda WS 115718624 4096 0.203
0.255192 dbthread 8623 sda WS 115718632 8192 0.207
0.255626 dbthread 8623 sda WS 144686440 4096 0.024
0.255913 ? 0 sda FF -1 0 0.119
0.256035 dbthread 8623 sda WS 144686448 4096 0.044
0.256207 ? 0 sda FF -1 0 0.105
0.317385 kworker/0:3 1667 sda N -1 0 0.417
0.474849 SettingsProvid 3532 sda WS 115718648 81920 0.216
0.475058 SettingsProvid 3532 sda WS 144686456 4096 0.027
0.535385 kworker/0:3 1667 sda N -1 0 0.410
0.770098 touch-main-loo 2349 sda R 8517944 4096 0.198
0.770364 touch-main-loo 2349 sda RA 8431168 4096 0.075
0.770469 touch-main-loo 2349 sda RA 8431176 8192 0.083The ELF audit produces:
$ readelf -d biosnoop
There is no dynamic section in this file.Therefore, the deployed tool does not require libelf.so.1, libz.so, or
other build-specific shared libraries on the device.
Platform scope
The current prototype uses an AArch64 GNU/Linux/glibc cross toolchain and runs the resulting fully static binaries on Android. This is an Android deployment workflow, not a native Android NDK/bionic build.
AArch64 GNU/Linux/glibc and Android NDK/bionic are different targets and should not be treated as interchangeable. Native NDK/bionic support, if desired, should be considered separately.
Successful execution also depends on target-specific conditions, including:
- a kernel with the required eBPF features;
- suitable BTF data for CO-RE relocation;
- root or the required Linux capabilities;
- compatible SELinux policy; and
- tracepoints, kprobes, and kernel symbols required by each tool.
Questions
- Is an optional fully static AArch64 build mode appropriate for BCC
libbpf-tools? - Should the implementation be integrated into the existing Makefile or kept in a separate build script?
- Should the project validate fully static output in CI by checking for
PT_INTERP,DT_NEEDED, and dynamic sections? - Should Android deployment documentation explicitly distinguish this GNU/Linux/glibc approach from native Android NDK/bionic support?
The prototype demonstrates that fully static libbpf-tools provide a simple
and practical deployment path for Android AArch64 devices without changing
the tools' functional source code.
Source: iovisor/bcc