tools/objtool/elf.c | 14 ++++++++++++++ tools/objtool/include/objtool/elf.h | 1 + tools/objtool/klp-diff.c | 15 +++++++++++++-- 3 files changed, 28 insertions(+), 2 deletions(-)
The following commit has been merged into the objtool/core branch of tip:
Commit-ID: d5b0f025281f287759820f57b7ba1bac7827b338
Gitweb: https://git.kernel.org/tip/d5b0f025281f287759820f57b7ba1bac7827b338
Author: Josh Poimboeuf <jpoimboe@kernel.org>
AuthorDate: Tue, 28 Apr 2026 14:34:23 -07:00
Committer: Josh Poimboeuf <jpoimboe@kernel.org>
CommitterDate: Mon, 04 May 2026 21:16:02 -07:00
objtool/klp: Fix pointer comparisons for rodata objects
klp-diff treats all rodata as uncorrelated, so any reference to it uses
a duplicated copy rather than using a KLP reloc.
For the contents of the data itself, a duplicated copy is fine.
However, pointer comparisons (e.g., f->f_op == &foo_ops) are broken.
Fix it by correlating non-anonymous rodata objects.
Also, use a new find_symbol_containing_inclusive() helper for matching
the end of a symbol so bounds calculations don't get broken, for the
case where an array or other symbol's ending address is used as part of
a bounds calculation.
While these are really two distinct changes, they need to be done in the
same patch so as to avoid introducing bisection regressions.
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
tools/objtool/elf.c | 14 ++++++++++++++
tools/objtool/include/objtool/elf.h | 1 +
tools/objtool/klp-diff.c | 15 +++++++++++++--
3 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index 87c6e00..5a20dab 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -208,6 +208,20 @@ struct symbol *find_symbol_containing(const struct section *sec, unsigned long o
}
/*
+ * Also match the symbol end address which can be used for a bounds comparison.
+ */
+struct symbol *find_symbol_containing_inclusive(const struct section *sec,
+ unsigned long offset)
+{
+ struct symbol *sym = find_symbol_containing(sec, offset);
+
+ if (!sym && offset)
+ sym = find_symbol_containing(sec, offset - 1);
+
+ return sym;
+}
+
+/*
* Returns size of hole starting at @offset.
*/
int find_symbol_hole_containing(const struct section *sec, unsigned long offset)
diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h
index ab5f701..8a543ce 100644
--- a/tools/objtool/include/objtool/elf.h
+++ b/tools/objtool/include/objtool/elf.h
@@ -211,6 +211,7 @@ struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
struct symbol *find_symbol_by_name(const struct elf *elf, const char *name);
struct symbol *find_global_symbol_by_name(const struct elf *elf, const char *name);
struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset);
+struct symbol *find_symbol_containing_inclusive(const struct section *sec, unsigned long offset);
int find_symbol_hole_containing(const struct section *sec, unsigned long offset);
struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset);
struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 78633c9..bf37c65 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -386,6 +386,7 @@ static bool dont_correlate(struct symbol *sym)
is_uncorrelated_static_local(sym) ||
is_local_label(sym) ||
is_string_sec(sym->sec) ||
+ (is_rodata_sec(sym->sec) && !is_object_sym(sym)) ||
is_initcall_sym(sym) ||
is_addressable_sym(sym) ||
is_special_section(sym->sec) ||
@@ -979,7 +980,7 @@ static int convert_reloc_secsym_to_sym(struct elf *elf, struct reloc *reloc)
goto found_sym;
/* No dedicated section; find the symbol manually */
- sym = find_symbol_containing(sec, arch_adjusted_addend(reloc));
+ sym = find_symbol_containing_inclusive(sec, arch_adjusted_addend(reloc));
if (!sym) {
/*
* This is presumably an .altinstr_replacement section which is
@@ -989,6 +990,17 @@ static int convert_reloc_secsym_to_sym(struct elf *elf, struct reloc *reloc)
return 1;
/*
+ * .rodata is a mixed bag of named objects and anonymous data.
+ *
+ * Convert section symbol references to named object symbols
+ * when possible, to preserve pointer identity for const
+ * structs like file_operations. Otherwise a section symbol is
+ * fine.
+ */
+ if (is_rodata_sec(sec))
+ return 0;
+
+ /*
* This can happen for special section references to weak code
* whose symbol has been stripped by the linker.
*/
@@ -1009,7 +1021,6 @@ found_sym:
static bool is_uncorrelated_section(struct section *sec)
{
return is_string_sec(sec) ||
- strstarts(sec->name, ".rodata") ||
strstarts(sec->name, ".data..Lubsan") || /* GCC */
strstarts(sec->name, ".data..L__unnamed_"); /* Clang */
}
© 2016 - 2026 Red Hat, Inc.