From: Mark Korenberg via B4 Relay <devnull+socketpair.gmail.com@kernel.org>
To: Quentin Monnet <qmo@kernel.org>,
Alexei Starovoitov <ast@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, Mark Korenberg <socketpair@gmail.com>
Subject: [PATCH bpf-next v4 2/2] bpftool: Make the LLVM disassembler an optional runtime dependency
Date: Mon, 02 Nov 2026 17:44:12 +0500 [thread overview]
Message-ID: <20261102-bpftool-plugin-v4-2-5a853e973db9@gmail.com> (raw)
In-Reply-To: <20261102-bpftool-plugin-v4-0-5a853e973db9@gmail.com>
From: Mark Korenberg <socketpair@gmail.com>
libLLVM is only needed for "bpftool prog dump jited", yet it is a hard
dependency of bpftool: on Fedora 43, installing the ~730 KiB bpftool pulls
in ~140 MiB of llvm20-libs.
When libLLVM is a shared library, don't link bpftool with it. Instead,
disasm_init() loads it with dlopen(), under the name llvm-config reports
at build time, and resolves the few llvm-c functions bpftool uses with
dlsym(), like perf does for libcapstone. Distributions can then make LLVM
an optional dependency of bpftool.
"bpftool version" still reports "llvm" as a build time feature. Static
LLVM, and LLVM built with one library per component, are linked as before.
Link: https://github.com/libbpf/bpftool/issues/262
Suggested-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Mark Korenberg <socketpair@gmail.com>
---
tools/bpf/bpftool/Makefile | 10 ++++-
tools/bpf/bpftool/jit_disasm.c | 86 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 95 insertions(+), 1 deletion(-)
diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile
index b0f7168e7943..876bf3cf93e3 100644
--- a/tools/bpf/bpftool/Makefile
+++ b/tools/bpf/bpftool/Makefile
@@ -186,10 +186,18 @@ 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))
+ LIBLLVM_SO := $(shell $(LLVM_CONFIG) --libfiles $(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 ifeq ($(words $(LIBLLVM_SO)),1)
+ # Don't link with libLLVM.so. "prog dump jited" loads it with dlopen().
+ CFLAGS += -DLIBLLVM_SO='"$(notdir $(realpath $(LIBLLVM_SO)))"'
+ LIBS += -ldl
+ else
+ # LLVM built with BUILD_SHARED_LIBS=ON, one library per component
+ LIBS += $(shell $(LLVM_CONFIG) --libs $(LLVM_CONFIG_LIB_COMPONENTS))
endif
LDFLAGS += $(shell $(LLVM_CONFIG) --ldflags)
else
diff --git a/tools/bpf/bpftool/jit_disasm.c b/tools/bpf/bpftool/jit_disasm.c
index 5ff144ce84a1..2c646626e256 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,89 @@ 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 +219,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 +227,7 @@ int disasm_init(void)
LLVMInitializeAllDisassemblers();
return 0;
}
+#endif
#endif /* HAVE_LLVM_SUPPORT */
#ifdef HAVE_LIBBFD_SUPPORT
--
2.56.0
prev parent reply other threads:[~2026-11-02 12:44 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-02 12:44 [PATCH bpf-next v4 0/2] " Mark Korenberg via B4 Relay
2026-11-02 12:44 ` [PATCH bpf-next v4 1/2] bpftool: Fix disposal of the LLVM disassembler context Mark Korenberg via B4 Relay
2026-11-02 12:44 ` Mark Korenberg via B4 Relay [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=20261102-bpftool-plugin-v4-2-5a853e973db9@gmail.com \
--to=devnull+socketpair.gmail.com@kernel.org \
--cc=andrii@kernel.org \
--cc=ast@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®