[PATCH 1/1] objtool/klp: fix symbol ordering for data symbols
From: Joe Lawrence <joe.lawrence@redhat.com>
Date: 2026-07-10 15:30:54
Subsystem:
objtool, the rest · Maintainers:
Josh Poimboeuf, Peter Zijlstra, Linus Torvalds
The find_sympos() function calculates a sympos (symbol position) used by
livepatch to disambiguate duplicate symbol names. At runtime, kallsyms
iterates symbols sorted by address, so sympos must reflect that order.
For function symbols, there's already a workaround that counts
.text.unlikely symbols before other .text symbols, matching the linker
script's section ordering.
Data symbols suffer the same problem: the linker script places sections
in this order:
.data..ro_after_init (lowest address)
.data* sections
.bss* sections (highest address)
However, vmlinux.o's symbol table is ordered by object file link order
(kernel/ before fs/, etc.), which can differ from the final address
order.
Extend the existing section ordering workaround to handle data symbols,
counting .data..ro_after_init first, then other .data, then .bss.
Reported-by: Ben Procknow <redacted>
Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffing object files")
Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com>
---
tools/objtool/klp-diff.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index c2c4e4968bc2..1c6f9f6d7565 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c@@ -509,6 +509,46 @@ static unsigned long find_sympos(struct elf *elf, struct symbol *sym) has_dup = true; } } + } else if (vmlinux && is_object_sym(sym)) { + /* + * HACK: Similarly, data symbol ordering can differ between + * vmlinux.o and vmlinux. The linker script places sections: + * .data..ro_after_init (lowest address) + * .data* sections + * .bss* sections (highest address) + * Count in that order. + */ + for_each_sym(elf, s) { + if (strstarts(s->sec->name, ".data..ro_after_init") && + !strcmp(s->name, sym->name)) { + nr_matches++; + if (s == sym) + sympos = nr_matches; + else + has_dup = true; + } + } + for_each_sym(elf, s) { + if (!strstarts(s->sec->name, ".data..ro_after_init") && + !strstarts(s->sec->name, ".bss") && + !strcmp(s->name, sym->name)) { + nr_matches++; + if (s == sym) + sympos = nr_matches; + else + has_dup = true; + } + } + for_each_sym(elf, s) { + if (strstarts(s->sec->name, ".bss") && + !strcmp(s->name, sym->name)) { + nr_matches++; + if (s == sym) + sympos = nr_matches; + else + has_dup = true; + } + } } else { for_each_sym(elf, s) { if (!strcmp(s->name, sym->name)) {
--
2.54.0