[PATCH 48/48] objtool/klp: Cache dont_correlate() result

From: Josh Poimboeuf

Date: Thu Apr 23 2026 - 00:19:42 EST


Cache the dont_correlate() result once per symbol at the start of
correlate_symbols(). This reduces klp diff time on an arm64 LTO
vmlinux.o from 2m51s to 35s.

Signed-off-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
---
tools/objtool/include/objtool/elf.h | 1 +
tools/objtool/klp-diff.c | 29 +++++++++++++++++------------
2 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index 21441bd72971..fb4fec7d8a6e 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -95,6 +95,7 @@ struct symbol {
u8 changed : 1;
u8 included : 1;
u8 klp : 1;
+ u8 dont_correlate : 1;
struct list_head pv_target;
struct reloc *relocs;
struct section *group_sec;
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 420d05633aba..a848015b477c 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -566,7 +566,7 @@ static struct symbol *find_twin(struct elfs *e, struct symbol *sym1)

/* Count orig candidates */
for_each_sym_by_demangled_name(e->orig, sym1->demangled_name, sym2) {
- if (sym2->twin || sym1->type != sym2->type || dont_correlate(sym2) ||
+ if (sym2->twin || sym1->type != sym2->type || sym2->dont_correlate ||
(!maybe_same_file(sym1, sym2)))
continue;

@@ -592,7 +592,7 @@ static struct symbol *find_twin(struct elfs *e, struct symbol *sym1)

/* Count patched candidates */
for_each_sym_by_demangled_name(e->patched, sym1->demangled_name, sym2) {
- if (sym2->twin || sym1->type != sym2->type || dont_correlate(sym2))
+ if (sym2->twin || sym1->type != sym2->type || sym2->dont_correlate)
continue;

/* Level 1 */
@@ -728,7 +728,7 @@ static struct symbol *find_twin_suffixed(struct elf *elf, struct symbol *sym1)
return NULL;

for_each_sym_by_name(elf, name, sym2) {
- if (sym2->twin || sym1->type != sym2->type || dont_correlate(sym2))
+ if (sym2->twin || sym1->type != sym2->type || sym2->dont_correlate)
continue;
count++;
match = sym2;
@@ -762,7 +762,7 @@ static struct symbol *find_twin_positional(struct elfs *e, struct symbol *sym1)
struct symbol *sym2, *match = NULL;

for_each_sym_by_demangled_name(e->orig, sym1->demangled_name, sym2) {
- if (sym2->twin || sym1->type != sym2->type || dont_correlate(sym2) ||
+ if (sym2->twin || sym1->type != sym2->type || sym2->dont_correlate ||
!maybe_same_file(sym1, sym2))
continue;
if (is_tu_local_sym(sym1) != is_tu_local_sym(sym2) ||
@@ -774,7 +774,7 @@ static struct symbol *find_twin_positional(struct elfs *e, struct symbol *sym1)
}

for_each_sym_by_demangled_name(e->patched, sym1->demangled_name, sym2) {
- if (sym2->twin || sym1->type != sym2->type || dont_correlate(sym2) ||
+ if (sym2->twin || sym1->type != sym2->type || sym2->dont_correlate ||
!maybe_same_file(sym1, sym2))
continue;
if (is_tu_local_sym(sym1) != is_tu_local_sym(sym2) ||
@@ -806,6 +806,11 @@ static int correlate_symbols(struct elfs *e)
struct symbol *sym1, *sym2;
bool progress;

+ for_each_sym(e->orig, sym1)
+ sym1->dont_correlate = dont_correlate(sym1);
+ for_each_sym(e->patched, sym2)
+ sym2->dont_correlate = dont_correlate(sym2);
+
/* Correlate FILE symbols */
file1_sym = first_file_symbol(e->orig);
file2_sym = first_file_symbol(e->patched);
@@ -846,7 +851,7 @@ static int correlate_symbols(struct elfs *e)
do {
progress = false;
for_each_sym(e->orig, sym1) {
- if (sym1->twin || dont_correlate(sym1))
+ if (sym1->twin || sym1->dont_correlate)
continue;
sym2 = find_twin(e, sym1);
if (!sym2)
@@ -860,7 +865,7 @@ static int correlate_symbols(struct elfs *e)
return -1;

for_each_sym(e->orig, sym1) {
- if (sym1->twin || dont_correlate(sym1))
+ if (sym1->twin || sym1->dont_correlate)
continue;
sym2 = find_twin_suffixed(e->patched, sym1);
if (!sym2)
@@ -872,7 +877,7 @@ static int correlate_symbols(struct elfs *e)
} while (progress);

for_each_sym(e->orig, sym1) {
- if (sym1->twin || dont_correlate(sym1))
+ if (sym1->twin || sym1->dont_correlate)
continue;
sym2 = find_twin_positional(e, sym1);
if (!sym2)
@@ -882,7 +887,7 @@ static int correlate_symbols(struct elfs *e)
}

for_each_sym(e->orig, sym1) {
- if (sym1->twin || dont_correlate(sym1))
+ if (sym1->twin || sym1->dont_correlate)
continue;
WARN("no correlation: %s", sym1->name);
}
@@ -1102,7 +1107,7 @@ static int mark_changed_functions(struct elfs *e)

/* Find changed functions */
for_each_sym(e->orig, orig_sym) {
- if (dont_correlate(orig_sym))
+ if (orig_sym->dont_correlate)
continue;

patched_sym = orig_sym->twin;
@@ -1123,7 +1128,7 @@ static int mark_changed_functions(struct elfs *e)

/* Find added functions and print them */
for_each_sym(e->patched, patched_sym) {
- if (!is_func_sym(patched_sym) || dont_correlate(patched_sym))
+ if (!is_func_sym(patched_sym) || patched_sym->dont_correlate)
continue;

if (!patched_sym->twin) {
@@ -1263,7 +1268,7 @@ static bool klp_reloc_needed(struct reloc *patched_reloc)
struct export *export;

/* no external symbol to reference */
- if (dont_correlate(patched_sym))
+ if (patched_sym->dont_correlate)
return false;

/* For included functions, a regular reloc will do. */
--
2.53.0