Re: [PATCH v3 bpf-next 07/13] libbpf: Use CO-RE in the kernel in light skeleton.
From: Andrii Nakryiko <hidden>
Date: 2021-11-23 00:04:04
On Fri, Nov 19, 2021 at 7:33 PM Alexei Starovoitov [off-list ref] wrote:
From: Alexei Starovoitov <ast@kernel.org> Without lskel the CO-RE relocations are processed by libbpf before any other work is done. Instead, when lskel is needed, remember relocation as RELO_CORE kind. Then when loader prog is generated for a given bpf program pass CO-RE relos of that program to gen loader via bpf_gen__record_relo_core(). The gen loader will remember them as-is and pass it later as-is into the kernel. The normal libbpf flow is to process CO-RE early before call relos happen. In case of gen_loader the core relos have to be added to other relos to be copied together when bpf static function is appended in different places to other main bpf progs. During the copy the append_subprog_relos() will adjust insn_idx for normal relos and for RELO_CORE kind too. When that is done each struct reloc_desc has good relos for specific main prog. Signed-off-by: Alexei Starovoitov <ast@kernel.org> --- tools/lib/bpf/bpf_gen_internal.h | 3 + tools/lib/bpf/gen_loader.c | 41 +++++++++++- tools/lib/bpf/libbpf.c | 108 ++++++++++++++++++++++--------- 3 files changed, 119 insertions(+), 33 deletions(-)
[...]
quoted hunk ↗ jump to hunk
if (relo->kind != BPF_CORE_TYPE_ID_LOCAL &&@@ -5653,6 +5679,9 @@ bpf_object__relocate_data(struct bpf_object *obj, struct bpf_program *prog) case RELO_CALL: /* handled already */ break; + case RELO_CORE: + /* will be handled by bpf_program_record_relos() */ + break; default: pr_warn("prog '%s': relo #%d: bad relo type %d\n", prog->name, i, relo->type);@@ -6090,6 +6119,35 @@ bpf_object__free_relocs(struct bpf_object *obj) } } +static int cmp_relocs(const void *_a, const void *_b) +{ + const struct reloc_desc *a = _a; + const struct reloc_desc *b = _b; + + if (a->insn_idx != b->insn_idx) + return a->insn_idx < b->insn_idx ? -1 : 1; + + /* no two relocations should have the same insn_idx, but ... */ + if (a->type != b->type) + return a->type < b->type ? -1 : 1; + + return 0; +} + +static void bpf_object__sort_relos(struct bpf_object *obj) +{ + int i; + + for (i = 0; i < obj->nr_programs; i++) { + struct bpf_program *p = &obj->programs[i]; + + if (!p->nr_reloc) + continue; + + qsort(p->reloc_desc, p->nr_reloc, sizeof(*p->reloc_desc), cmp_relocs); + } +} + static int bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_path) {@@ -6104,6 +6162,8 @@ bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_path) err); return err; } + if (obj->gen_loader) + bpf_object__sort_relos(obj);
libbpf sorts relos because it does binary search on them (see find_prog_insn_relo). Kernel doesn't seem to enforce the order of CO-RE relocations, so there doesn't seem to be a need to sort them. Is there any reason you wanted to sort them? Does light skeleton's generated code rely on some ordering? If yes, let's add a small comment to document this.
}
/* Before relocating calls pre-process relocations and mark[...]