Re: [PATCH bpf-next v2 2/8] libbpf: Add typeless ksym support to gen_loader
From: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Date: 2021-10-14 17:53:46
Also in:
bpf
On Thu, Oct 14, 2021 at 10:09:43PM IST, Song Liu wrote:
quoted
On Oct 13, 2021, at 12:33 AM, Kumar Kartikeya Dwivedi [off-list ref] wrote: This uses the bpf_kallsyms_lookup_name helper added in previous patches to relocate typeless ksyms. The return value ENOENT can be ignored, and the value written to 'res' can be directly stored to the insn, as it is overwritten to 0 on lookup failure. For repeating symbols, we can simply copy the previously populated bpf_insn. Also, we need to take care to not close fds for typeless ksym_desc, so reuse the 'off' member's space to add a marker for typeless ksym and use that to skip them in cleanup_relos. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>[...]quoted
} +/* Expects: + * BPF_REG_8 - pointer to instruction + */ +static void emit_relo_ksym_typeless(struct bpf_gen *gen, + struct ksym_relo_desc *relo, int insn)This function has quite some duplicated logic as emit_relo_ksym_btf(). I guess we can somehow reuse the code here. Say, we pull changes from 3/8 first to handle weak type. Then we extend the function to handle typeless. Would this work?
Ok, will put both into the same function in the next version. Though the part between:
quoted
+{ + struct ksym_desc *kdesc; + + kdesc = get_ksym_desc(gen, relo); + if (!kdesc) + return; + /* try to copy from existing ldimm64 insn */ + if (kdesc->ref > 1) { + move_blob2blob(gen, insn + offsetof(struct bpf_insn, imm), 4, + kdesc->insn + offsetof(struct bpf_insn, imm)); + move_blob2blob(gen, insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm), 4, + kdesc->insn + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm));
this and ...
quoted
+ goto log; + } + /* remember insn offset, so we can copy ksym addr later */ + kdesc->insn = insn; + /* skip typeless ksym_desc in fd closing loop in cleanup_relos */ + kdesc->typeless = true; + emit_bpf_kallsyms_lookup_name(gen, relo); + emit(gen, BPF_JMP_IMM(BPF_JEQ, BPF_REG_7, -ENOENT, 1)); + emit_check_err(gen); + /* store lower half of addr into insn[insn_idx].imm */ + emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_8, BPF_REG_9, offsetof(struct bpf_insn, imm))); + /* store upper half of addr into insn[insn_idx + 1].imm */ + emit(gen, BPF_ALU64_IMM(BPF_RSH, BPF_REG_9, 32)); + emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_8, BPF_REG_9, + sizeof(struct bpf_insn) + offsetof(struct bpf_insn, imm)));
... this won't overlap (so it will have to jump into the else branch to clear_src_reg).
e.g. it looks something like this:
if (kdesc->ref > 1) {
move...
if (!relo->is_typeless)
...
goto clear_src_reg;
}
kdesc->insn = insn;
...
if (relo->is_typeless) {
...
} else {
...
clear_src_reg:
...
}
so it looked better to split into separate functions (maybe we can just move the
logging part to common helper? the rest is just duplicating the inital get and
move_blob2blob).
quoted
+log: + if (!gen->log_level) + return; + emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_8, + offsetof(struct bpf_insn, imm))); + emit(gen, BPF_LDX_MEM(BPF_H, BPF_REG_9, BPF_REG_8, sizeof(struct bpf_insn) + + offsetof(struct bpf_insn, imm))); + debug_regs(gen, BPF_REG_7, BPF_REG_9, " var t=0 w=%d (%s:count=%d): imm[0]: %%d, imm[1]: %%d", + relo->is_weak, relo->name, kdesc->ref); + emit(gen, BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_8, offsetofend(struct bpf_insn, code))); + debug_regs(gen, BPF_REG_9, -1, " var t=0 w=%d (%s:count=%d): insn.reg", + relo->is_weak, relo->name, kdesc->ref);[...]quoted
+++ b/tools/lib/bpf/libbpf.c@@ -6355,17 +6355,14 @@ static int bpf_program__record_externs(struct bpf_program *prog)case RELO_EXTERN_VAR: if (ext->type != EXT_KSYM) continue; - if (!ext->ksym.type_id) { - pr_warn("typeless ksym %s is not supported yet\n", - ext->name); - return -ENOTSUP; - } - bpf_gen__record_extern(obj->gen_loader, ext->name, ext->is_weak, + bpf_gen__record_extern(obj->gen_loader, ext->name, + ext->is_weak, !ext->ksym.type_id, BTF_KIND_VAR, relo->insn_idx); break; case RELO_EXTERN_FUNC: - bpf_gen__record_extern(obj->gen_loader, ext->name, ext->is_weak, - BTF_KIND_FUNC, relo->insn_idx); + bpf_gen__record_extern(obj->gen_loader, ext->name, + ext->is_weak, 0, BTF_KIND_FUNC,nit: Prefer use "false" for bool arguments.quoted
+ relo->insn_idx); break; default: continue; -- 2.33.0
-- Kartikeya