Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpftool: Add `gen object` command to perform BPF static linking

Add `bpftool gen object <output-file> <input_file>...` command to statically
link multiple BPF ELF object files into a single output BPF ELF object file.

This patch also updates bash completions and man page. Man page gets a short
section on `gen object` command, but also updates the skeleton example to show
off workflow for BPF application with two .bpf.c files, compiled individually
with Clang, then resulting object files are linked together with `gen object`,
and then final object file is used to generate usable BPF skeleton. This
should help new users understand realistic workflow w.r.t. compiling
mutli-file BPF application.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Reviewed-by: Quentin Monnet <quentin@isovalent.com>
Link: https://lore.kernel.org/bpf/20210318194036.3521577-10-andrii@kernel.org

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
d80b2fcb c4122665

+100 -16
+51 -14
tools/bpf/bpftool/Documentation/bpftool-gen.rst
··· 14 14 15 15 *OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] } 16 16 17 - *COMMAND* := { **skeleton** | **help** } 17 + *COMMAND* := { **object** | **skeleton** | **help** } 18 18 19 19 GEN COMMANDS 20 20 ============= 21 21 22 + | **bpftool** **gen object** *OUTPUT_FILE* *INPUT_FILE* [*INPUT_FILE*...] 22 23 | **bpftool** **gen skeleton** *FILE* [**name** *OBJECT_NAME*] 23 24 | **bpftool** **gen help** 24 25 25 26 DESCRIPTION 26 27 =========== 28 + **bpftool gen object** *OUTPUT_FILE* *INPUT_FILE* [*INPUT_FILE*...] 29 + Statically link (combine) together one or more *INPUT_FILE*'s 30 + into a single resulting *OUTPUT_FILE*. All the files involved 31 + are BPF ELF object files. 32 + 33 + The rules of BPF static linking are mostly the same as for 34 + user-space object files, but in addition to combining data 35 + and instruction sections, .BTF and .BTF.ext (if present in 36 + any of the input files) data are combined together. .BTF 37 + data is deduplicated, so all the common types across 38 + *INPUT_FILE*'s will only be represented once in the resulting 39 + BTF information. 40 + 41 + BPF static linking allows to partition BPF source code into 42 + individually compiled files that are then linked into 43 + a single resulting BPF object file, which can be used to 44 + generated BPF skeleton (with **gen skeleton** command) or 45 + passed directly into **libbpf** (using **bpf_object__open()** 46 + family of APIs). 47 + 27 48 **bpftool gen skeleton** *FILE* 28 49 Generate BPF skeleton C header file for a given *FILE*. 29 50 ··· 154 133 155 134 EXAMPLES 156 135 ======== 157 - **$ cat example.c** 136 + **$ cat example1.bpf.c** 158 137 159 138 :: 160 139 161 140 #include <stdbool.h> 162 141 #include <linux/ptrace.h> 163 142 #include <linux/bpf.h> 164 - #include "bpf_helpers.h" 143 + #include <bpf/bpf_helpers.h> 165 144 166 145 const volatile int param1 = 42; 167 146 bool global_flag = true; 168 147 struct { int x; } data = {}; 169 - 170 - struct { 171 - __uint(type, BPF_MAP_TYPE_HASH); 172 - __uint(max_entries, 128); 173 - __type(key, int); 174 - __type(value, long); 175 - } my_map SEC(".maps"); 176 148 177 149 SEC("raw_tp/sys_enter") 178 150 int handle_sys_enter(struct pt_regs *ctx) ··· 178 164 return 0; 179 165 } 180 166 167 + **$ cat example2.bpf.c** 168 + 169 + :: 170 + 171 + #include <linux/ptrace.h> 172 + #include <linux/bpf.h> 173 + #include <bpf/bpf_helpers.h> 174 + 175 + struct { 176 + __uint(type, BPF_MAP_TYPE_HASH); 177 + __uint(max_entries, 128); 178 + __type(key, int); 179 + __type(value, long); 180 + } my_map SEC(".maps"); 181 + 181 182 SEC("raw_tp/sys_exit") 182 183 int handle_sys_exit(struct pt_regs *ctx) 183 184 { ··· 202 173 } 203 174 204 175 This is example BPF application with two BPF programs and a mix of BPF maps 205 - and global variables. 176 + and global variables. Source code is split across two source code files. 206 177 207 - **$ bpftool gen skeleton example.o** 178 + **$ clang -target bpf -g example1.bpf.c -o example1.bpf.o** 179 + **$ clang -target bpf -g example2.bpf.c -o example2.bpf.o** 180 + **$ bpftool gen object example.bpf.o example1.bpf.o example2.bpf.o** 181 + 182 + This set of commands compiles *example1.bpf.c* and *example2.bpf.c* 183 + individually and then statically links respective object files into the final 184 + BPF ELF object file *example.bpf.o*. 185 + 186 + **$ bpftool gen skeleton example.bpf.o name example | tee example.skel.h** 208 187 209 188 :: 210 189 ··· 267 230 268 231 #endif /* __EXAMPLE_SKEL_H__ */ 269 232 270 - **$ cat example_user.c** 233 + **$ cat example.c** 271 234 272 235 :: 273 236 ··· 310 273 return err; 311 274 } 312 275 313 - **# ./example_user** 276 + **# ./example** 314 277 315 278 :: 316 279
+5 -1
tools/bpf/bpftool/bash-completion/bpftool
··· 981 981 ;; 982 982 gen) 983 983 case $command in 984 + object) 985 + _filedir 986 + return 0 987 + ;; 984 988 skeleton) 985 989 case $prev in 986 990 $command) ··· 999 995 ;; 1000 996 *) 1001 997 [[ $prev == $object ]] && \ 1002 - COMPREPLY=( $( compgen -W 'skeleton help' -- "$cur" ) ) 998 + COMPREPLY=( $( compgen -W 'object skeleton help' -- "$cur" ) ) 1003 999 ;; 1004 1000 esac 1005 1001 ;;
+44 -1
tools/bpf/bpftool/gen.c
··· 614 614 return err; 615 615 } 616 616 617 + static int do_object(int argc, char **argv) 618 + { 619 + struct bpf_linker *linker; 620 + const char *output_file, *file; 621 + int err = 0; 622 + 623 + if (!REQ_ARGS(2)) { 624 + usage(); 625 + return -1; 626 + } 627 + 628 + output_file = GET_ARG(); 629 + 630 + linker = bpf_linker__new(output_file, NULL); 631 + if (!linker) { 632 + p_err("failed to create BPF linker instance"); 633 + return -1; 634 + } 635 + 636 + while (argc) { 637 + file = GET_ARG(); 638 + 639 + err = bpf_linker__add_file(linker, file); 640 + if (err) { 641 + p_err("failed to link '%s': %s (%d)", file, strerror(err), err); 642 + goto out; 643 + } 644 + } 645 + 646 + err = bpf_linker__finalize(linker); 647 + if (err) { 648 + p_err("failed to finalize ELF file: %s (%d)", strerror(err), err); 649 + goto out; 650 + } 651 + 652 + err = 0; 653 + out: 654 + bpf_linker__free(linker); 655 + return err; 656 + } 657 + 617 658 static int do_help(int argc, char **argv) 618 659 { 619 660 if (json_output) { ··· 663 622 } 664 623 665 624 fprintf(stderr, 666 - "Usage: %1$s %2$s skeleton FILE [name OBJECT_NAME]\n" 625 + "Usage: %1$s %2$s object OUTPUT_FILE INPUT_FILE [INPUT_FILE...]\n" 626 + " %1$s %2$s skeleton FILE [name OBJECT_NAME]\n" 667 627 " %1$s %2$s help\n" 668 628 "\n" 669 629 " " HELP_SPEC_OPTIONS "\n" ··· 675 633 } 676 634 677 635 static const struct cmd cmds[] = { 636 + { "object", do_object }, 678 637 { "skeleton", do_skeleton }, 679 638 { "help", do_help }, 680 639 { 0 }