[PATCH v3 2/9] objtool/klp: Fix size of empty special section entries

From: Josh Poimboeuf

Date: Fri Aug 07 2026 - 17:39:06 EST


create_fake_symbols() sizes each ANNOTATE_DATA_SPECIAL entry from the
offset of the next annotation, falling back to the end of the section
for the last entry. But the last entry is detected by a zero size,
which also happens for an *empty* entry: ALTERNATIVE(oldinstr, "", ft)
still annotates its zero-length replacement, at the same offset as the
next entry's annotation.

So every empty replacement gets a fake symbol spanning the entire rest
of .altinstr_replacement. That's harmless today only because
find_symbol_containing() picks the smaller of two overlapping symbols.

Track whether a next annotation was found rather than inferring it from
the size. A zero-length fake symbol is fine: find_symbol_containing()
skips those, so the properly sized symbol at the same offset still wins.

Fixes: dd590d4d57eb ("objtool/klp: Introduce klp diff subcommand for diffing object files")
Acked-by: Song Liu <song@xxxxxxxxxx>
Signed-off-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
---
tools/objtool/klp-diff.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 492d7a012cffe..38fae861d12c7 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -1627,13 +1627,17 @@ static int create_fake_symbols(struct elf *elf)
for_each_reloc(sec->rsec, reloc) {
unsigned long offset, size;
struct reloc *next_reloc;
+ bool last = true;

if (annotype(elf, sec, reloc) != ANNOTYPE_DATA_SPECIAL)
continue;

offset = reloc_addend(reloc);

- size = 0;
+ /*
+ * Find the start of the next entry so the fake symbol size can
+ * be calculated.
+ */
next_reloc = reloc;
for_each_reloc_continue(sec->rsec, next_reloc) {
if (annotype(elf, sec, next_reloc) != ANNOTYPE_DATA_SPECIAL ||
@@ -1641,10 +1645,15 @@ static int create_fake_symbols(struct elf *elf)
continue;

size = reloc_addend(next_reloc) - offset;
+ last = false;
break;
}

- if (!size)
+ /*
+ * If no next entry found, this is the last entry, so its size
+ * is from the current offset to the end of the section.
+ */
+ if (last)
size = sec_size(reloc->sym->sec) - offset;

if (create_fake_symbol(elf, reloc->sym->sec, offset, size))
--
2.54.0