mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-09 06:43:09 +00:00
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
This commit is contained in:
parent
c412266545
commit
d80b2fcbe0
@ -14,16 +14,37 @@ SYNOPSIS
|
||||
|
||||
*OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] }
|
||||
|
||||
*COMMAND* := { **skeleton** | **help** }
|
||||
*COMMAND* := { **object** | **skeleton** | **help** }
|
||||
|
||||
GEN COMMANDS
|
||||
=============
|
||||
|
||||
| **bpftool** **gen object** *OUTPUT_FILE* *INPUT_FILE* [*INPUT_FILE*...]
|
||||
| **bpftool** **gen skeleton** *FILE* [**name** *OBJECT_NAME*]
|
||||
| **bpftool** **gen help**
|
||||
|
||||
DESCRIPTION
|
||||
===========
|
||||
**bpftool gen object** *OUTPUT_FILE* *INPUT_FILE* [*INPUT_FILE*...]
|
||||
Statically link (combine) together one or more *INPUT_FILE*'s
|
||||
into a single resulting *OUTPUT_FILE*. All the files involved
|
||||
are BPF ELF object files.
|
||||
|
||||
The rules of BPF static linking are mostly the same as for
|
||||
user-space object files, but in addition to combining data
|
||||
and instruction sections, .BTF and .BTF.ext (if present in
|
||||
any of the input files) data are combined together. .BTF
|
||||
data is deduplicated, so all the common types across
|
||||
*INPUT_FILE*'s will only be represented once in the resulting
|
||||
BTF information.
|
||||
|
||||
BPF static linking allows to partition BPF source code into
|
||||
individually compiled files that are then linked into
|
||||
a single resulting BPF object file, which can be used to
|
||||
generated BPF skeleton (with **gen skeleton** command) or
|
||||
passed directly into **libbpf** (using **bpf_object__open()**
|
||||
family of APIs).
|
||||
|
||||
**bpftool gen skeleton** *FILE*
|
||||
Generate BPF skeleton C header file for a given *FILE*.
|
||||
|
||||
@ -133,26 +154,19 @@ OPTIONS
|
||||
|
||||
EXAMPLES
|
||||
========
|
||||
**$ cat example.c**
|
||||
**$ cat example1.bpf.c**
|
||||
|
||||
::
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/bpf.h>
|
||||
#include "bpf_helpers.h"
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
const volatile int param1 = 42;
|
||||
bool global_flag = true;
|
||||
struct { int x; } data = {};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 128);
|
||||
__type(key, int);
|
||||
__type(value, long);
|
||||
} my_map SEC(".maps");
|
||||
|
||||
SEC("raw_tp/sys_enter")
|
||||
int handle_sys_enter(struct pt_regs *ctx)
|
||||
{
|
||||
@ -164,6 +178,21 @@ EXAMPLES
|
||||
return 0;
|
||||
}
|
||||
|
||||
**$ cat example2.bpf.c**
|
||||
|
||||
::
|
||||
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 128);
|
||||
__type(key, int);
|
||||
__type(value, long);
|
||||
} my_map SEC(".maps");
|
||||
|
||||
SEC("raw_tp/sys_exit")
|
||||
int handle_sys_exit(struct pt_regs *ctx)
|
||||
{
|
||||
@ -173,9 +202,17 @@ EXAMPLES
|
||||
}
|
||||
|
||||
This is example BPF application with two BPF programs and a mix of BPF maps
|
||||
and global variables.
|
||||
and global variables. Source code is split across two source code files.
|
||||
|
||||
**$ bpftool gen skeleton example.o**
|
||||
**$ clang -target bpf -g example1.bpf.c -o example1.bpf.o**
|
||||
**$ clang -target bpf -g example2.bpf.c -o example2.bpf.o**
|
||||
**$ bpftool gen object example.bpf.o example1.bpf.o example2.bpf.o**
|
||||
|
||||
This set of commands compiles *example1.bpf.c* and *example2.bpf.c*
|
||||
individually and then statically links respective object files into the final
|
||||
BPF ELF object file *example.bpf.o*.
|
||||
|
||||
**$ bpftool gen skeleton example.bpf.o name example | tee example.skel.h**
|
||||
|
||||
::
|
||||
|
||||
@ -230,7 +267,7 @@ and global variables.
|
||||
|
||||
#endif /* __EXAMPLE_SKEL_H__ */
|
||||
|
||||
**$ cat example_user.c**
|
||||
**$ cat example.c**
|
||||
|
||||
::
|
||||
|
||||
@ -273,7 +310,7 @@ and global variables.
|
||||
return err;
|
||||
}
|
||||
|
||||
**# ./example_user**
|
||||
**# ./example**
|
||||
|
||||
::
|
||||
|
||||
|
@ -981,6 +981,10 @@ _bpftool()
|
||||
;;
|
||||
gen)
|
||||
case $command in
|
||||
object)
|
||||
_filedir
|
||||
return 0
|
||||
;;
|
||||
skeleton)
|
||||
case $prev in
|
||||
$command)
|
||||
@ -995,7 +999,7 @@ _bpftool()
|
||||
;;
|
||||
*)
|
||||
[[ $prev == $object ]] && \
|
||||
COMPREPLY=( $( compgen -W 'skeleton help' -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W 'object skeleton help' -- "$cur" ) )
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
@ -614,6 +614,47 @@ static int do_skeleton(int argc, char **argv)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int do_object(int argc, char **argv)
|
||||
{
|
||||
struct bpf_linker *linker;
|
||||
const char *output_file, *file;
|
||||
int err = 0;
|
||||
|
||||
if (!REQ_ARGS(2)) {
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
output_file = GET_ARG();
|
||||
|
||||
linker = bpf_linker__new(output_file, NULL);
|
||||
if (!linker) {
|
||||
p_err("failed to create BPF linker instance");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (argc) {
|
||||
file = GET_ARG();
|
||||
|
||||
err = bpf_linker__add_file(linker, file);
|
||||
if (err) {
|
||||
p_err("failed to link '%s': %s (%d)", file, strerror(err), err);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
err = bpf_linker__finalize(linker);
|
||||
if (err) {
|
||||
p_err("failed to finalize ELF file: %s (%d)", strerror(err), err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
out:
|
||||
bpf_linker__free(linker);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int do_help(int argc, char **argv)
|
||||
{
|
||||
if (json_output) {
|
||||
@ -622,7 +663,8 @@ static int do_help(int argc, char **argv)
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"Usage: %1$s %2$s skeleton FILE [name OBJECT_NAME]\n"
|
||||
"Usage: %1$s %2$s object OUTPUT_FILE INPUT_FILE [INPUT_FILE...]\n"
|
||||
" %1$s %2$s skeleton FILE [name OBJECT_NAME]\n"
|
||||
" %1$s %2$s help\n"
|
||||
"\n"
|
||||
" " HELP_SPEC_OPTIONS "\n"
|
||||
@ -633,6 +675,7 @@ static int do_help(int argc, char **argv)
|
||||
}
|
||||
|
||||
static const struct cmd cmds[] = {
|
||||
{ "object", do_object },
|
||||
{ "skeleton", do_skeleton },
|
||||
{ "help", do_help },
|
||||
{ 0 }
|
||||
|
Loading…
Reference in New Issue
Block a user