From: "Alexei Starovoitov" <alexei.starovoitov@gmail.com>
To: <socketpair@gmail.com>, "Quentin Monnet" <qmo@kernel.org>,
"Daniel Borkmann" <daniel@iogearbox.net>,
"Andrii Nakryiko" <andrii@kernel.org>,
"Martin KaFai Lau" <martin.lau@linux.dev>,
"Eduard Zingerman" <eddyz87@gmail.com>,
"Kumar Kartikeya Dwivedi" <memxor@gmail.com>,
"Song Liu" <song@kernel.org>,
"Yonghong Song" <yonghong.song@linux.dev>,
"Jiri Olsa" <jolsa@kernel.org>,
"Nathan Chancellor" <nathan@kernel.org>,
"Bill Wendling" <morbo@google.com>,
"Justin Stitt" <justinstitt@google.com>,
"Emil Tsalapatis" <emil@etsalapatis.com>,
"Ihor Solodrai" <ihor.solodrai@linux.dev>,
"Nick Desaulniers" <ndesaulniers@google.com>
Cc: <linux-kernel@vger.kernel.org>, <bpf@vger.kernel.org>,
<llvm@lists.linux.dev>
Subject: Re: [PATCH bpf-next v3 2/2] bpftool: Make the LLVM disassembler an optional runtime dependency
Date: Thu, 29 Oct 2026 15:24:22 +0000 [thread overview]
Message-ID: <DMHFCN3J36VN.2JJEE30A07C0Z@gmail.com> (raw)
In-Reply-To: <20261029-bpftool-plugin-v3-2-87af799da40a@gmail.com>
On Thu, Oct 29, 2026 at 06:05 AM Mark Korenberg via B4 Relay <devnull+socketpair.gmail.com@kernel.org> wrote:
> Move the LLVM disassembler to a plugin, $(libdir)/bpftool/bpftool-llvm.so,
> that bpftool loads with dlopen() only when disassembling JITed programs.
> Distributions can then ship it as an optional package.
>
> The plugin exports a single structure of callbacks, with an ABI version
> checked by bpftool. bpftool looks for the plugin next to its own binary,
> then in its install directory, but not in the current directory since it
> usually runs as root. "bpftool version" reports "llvm" only if the plugin
> can be loaded.
This is overkill.
The plugin wraps 7 llvm-c functions and the target init calls.
bpftool can dlopen() libLLVM.so itself and dlsym() them.
perf does that for libcapstone. See
commit b5c9bcde61b8 ("perf capstone: Support for dlopen-ing libcapstone.so").
this patch dlopen(libLLVM.so)
----------------- -------------------------- ------------------
installed files bpftool, bpftool-llvm.so bpftool
who finds the lib llvm_plugin_find() ld.so
ABI to maintain struct bpftool_llvm_ops none
Makefile libdir, llvm-plugin-dir, one -D
install, uninstall rules
v1, v2 and v3 each look for the plugin in a different way.
The bpftool that the selftests build still doesn't find it.
selftests/bpf, selftests/hid, selftests/sched_ext and tools/sched_ext do:
make -C tools/bpf/bpftool prefix= DESTDIR=<dir>/ install-bin
bpftool <dir>/sbin/bpftool
plugin <dir>/lib/bpftool/bpftool-llvm.so
bpftool looks in <dir>/sbin, then /lib/bpftool
"prog dump jited" fails there with this patch.
"make install" in selftests/bpf copies only bpftool. The plugin stays behind.
In the diff below llvm-config gives the name of the library at build time.
ld.so finds it the same way as today.
The distro package recommends the LLVM libs and doesn't require them.
"bpftool version" keeps "llvm" as a compile time feature.
That's what common_options.rst says.
LLVM built with BUILD_SHARED_LIBS=ON is not handled.
Something like this (not even compile tested):
diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile
index b0f7168..7a49182 100644
--- a/tools/bpf/bpftool/Makefile
+++ b/tools/bpf/bpftool/Makefile
@@ -186,10 +186,15 @@ ifeq ($(HAS_LLVM),1)
# Makefile includes lib.mk which sets -D_GNU_SOURCE) which would cause
# compilation error due to redefinition. Let's filter it out here.
CFLAGS += $(filter-out -D_GNU_SOURCE,$(shell $(LLVM_CONFIG) --cflags))
- LIBS += $(shell $(LLVM_CONFIG) --libs $(LLVM_CONFIG_LIB_COMPONENTS))
ifeq ($(shell $(LLVM_CONFIG) --shared-mode),static)
+ LIBS += $(shell $(LLVM_CONFIG) --libs $(LLVM_CONFIG_LIB_COMPONENTS))
LIBS += $(shell $(LLVM_CONFIG) --system-libs $(LLVM_CONFIG_LIB_COMPONENTS))
LIBS += -lstdc++
+ else
+ # Don't link with libLLVM.so. "prog dump jited" loads it with dlopen().
+ LIBLLVM_SO := $(shell $(LLVM_CONFIG) --libfiles $(LLVM_CONFIG_LIB_COMPONENTS))
+ CFLAGS += -DLIBLLVM_SO='"$(notdir $(realpath $(LIBLLVM_SO)))"'
+ LIBS += -ldl
endif
LDFLAGS += $(shell $(LLVM_CONFIG) --ldflags)
else
diff --git a/tools/bpf/bpftool/jit_disasm.c b/tools/bpf/bpftool/jit_disasm.c
index 0454115..cca02cd 100644
--- a/tools/bpf/bpftool/jit_disasm.c
+++ b/tools/bpf/bpftool/jit_disasm.c
@@ -25,6 +25,7 @@
#include <bpf/libbpf.h>
#ifdef HAVE_LLVM_SUPPORT
+#include <dlfcn.h>
#include <llvm-c/Core.h>
#include <llvm-c/Disassembler.h>
#include <llvm-c/Target.h>
@@ -47,6 +48,88 @@ static int oper_count;
typedef LLVMDisasmContextRef disasm_ctx_t;
+#ifdef LIBLLVM_SO
+/*
+ * libLLVM.so is big and only "prog dump jited" needs it. bpftool is not linked
+ * with it. disasm_init() loads it.
+ */
+#define LLVM_FUNCS(F) \
+ F(LLVMCreateDisasm) \
+ F(LLVMCreateDisasmCPUFeatures) \
+ F(LLVMDisasmDispose) \
+ F(LLVMDisasmInstruction) \
+ F(LLVMDisposeMessage) \
+ F(LLVMGetDefaultTargetTriple) \
+ F(LLVMNormalizeTargetTriple)
+
+#define F(fn) static __typeof__(&fn) p_##fn;
+LLVM_FUNCS(F)
+#undef F
+
+static const struct {
+ const char *name;
+ void *ptr;
+} llvm_funcs[] = {
+#define F(fn) { #fn, &p_##fn },
+ LLVM_FUNCS(F)
+#undef F
+};
+
+/* The functions that LLVMInitializeAll*() in llvm-c/Target.h call */
+static const char * const llvm_init_funcs[] = {
+#define LLVM_TARGET(t) "LLVMInitialize" #t "TargetInfo", "LLVMInitialize" #t "TargetMC",
+#include <llvm/Config/Targets.def>
+#define LLVM_DISASSEMBLER(t) "LLVMInitialize" #t "Disassembler",
+#include <llvm/Config/Disassemblers.def>
+};
+
+#define LLVMCreateDisasm p_LLVMCreateDisasm
+#define LLVMCreateDisasmCPUFeatures p_LLVMCreateDisasmCPUFeatures
+#define LLVMDisasmDispose p_LLVMDisasmDispose
+#define LLVMDisasmInstruction p_LLVMDisasmInstruction
+#define LLVMDisposeMessage p_LLVMDisposeMessage
+#define LLVMGetDefaultTargetTriple p_LLVMGetDefaultTargetTriple
+#define LLVMNormalizeTargetTriple p_LLVMNormalizeTargetTriple
+
+static void *llvm_sym(void *lib, const char *name)
+{
+ void *sym = dlsym(lib, name);
+
+ if (!sym)
+ p_err("%s is not in %s", name, LIBLLVM_SO);
+ return sym;
+}
+
+int disasm_init(void)
+{
+ void (*init)(void);
+ void *lib, *sym;
+ size_t i;
+
+ lib = dlopen(LIBLLVM_SO, RTLD_NOW);
+ if (!lib) {
+ p_err("failed to load %s: %s", LIBLLVM_SO,
+ dlerror() ?: "unknown error");
+ return -1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(llvm_funcs); i++) {
+ sym = llvm_sym(lib, llvm_funcs[i].name);
+ if (!sym)
+ return -1;
+ *(void **)llvm_funcs[i].ptr = sym;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(llvm_init_funcs); i++) {
+ init = llvm_sym(lib, llvm_init_funcs[i]);
+ if (!init)
+ return -1;
+ init();
+ }
+ return 0;
+}
+#endif /* LIBLLVM_SO */
+
static int printf_json(char *s)
{
s = strtok(s, " \t");
@@ -135,6 +218,7 @@ disassemble_insn(disasm_ctx_t *ctx, unsigned char *image, ssize_t len, int pc,
return count;
}
+#ifndef LIBLLVM_SO
int disasm_init(void)
{
LLVMInitializeAllTargetInfos();
@@ -142,6 +226,7 @@ int disasm_init(void)
LLVMInitializeAllDisassemblers();
return 0;
}
+#endif
#endif /* HAVE_LLVM_SUPPORT */
#ifdef HAVE_LIBBFD_SUPPORT
Keep patch 1.
Also pls don't respin in 22 minutes only because a bot said something.
pw-bot: cr
prev parent reply other threads:[~2026-10-29 15:24 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-29 13:05 [PATCH bpf-next v3 0/2] " Mark Korenberg via B4 Relay
2026-10-29 13:05 ` [PATCH bpf-next v3 1/2] bpftool: Fix disposal of the LLVM disassembler context Mark Korenberg via B4 Relay
2026-10-29 13:05 ` [PATCH bpf-next v3 2/2] bpftool: Make the LLVM disassembler an optional runtime dependency Mark Korenberg via B4 Relay
2026-10-29 13:46 ` bot+bpf-ci
2026-10-29 15:24 ` Alexei Starovoitov [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=DMHFCN3J36VN.2JJEE30A07C0Z@gmail.com \
--to=alexei.starovoitov@gmail.com \
--cc=andrii@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=ihor.solodrai@linux.dev \
--cc=jolsa@kernel.org \
--cc=justinstitt@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=llvm@lists.linux.dev \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=morbo@google.com \
--cc=nathan@kernel.org \
--cc=ndesaulniers@google.com \
--cc=qmo@kernel.org \
--cc=socketpair@gmail.com \
--cc=song@kernel.org \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®