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")
Signed-off-by: Josh Poimboeuf <[email protected]>
---
 tools/objtool/klp-diff.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 492d7a012cffe..11e8f3ddbb0e6 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -1627,6 +1627,7 @@ 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;
@@ -1641,10 +1642,11 @@ static int create_fake_symbols(struct elf *elf)
                                continue;
 
                        size = reloc_addend(next_reloc) - offset;
+                       last = false;
                        break;
                }
 
-               if (!size)
+               if (last)
                        size = sec_size(reloc->sym->sec) - offset;
 
                if (create_fake_symbol(elf, reloc->sym->sec, offset, size))
-- 
2.54.0


Reply via email to