objtool/klp: Fix extraction of text annotations for alternatives

Objtool is failing to extract text annotations which reference
.altinstr_replacement instructions:

  1) Alternative replacement fake symbols are NOTYPE rather than FUNC,
     and they don't have sym->included set, thus they aren't recognized
     by should_keep_special_sym().

  2) .discard.annotate_insn gets processed before .altinstr_replacement,
     so the referenced (fake) symbols don't have clones yet.

Fix the first issue by checking for a valid clone instead of
sym->included and by accepting NOTYPE symbols when processing
.discard.annotate_insn.

Fix the second issue by deferring text annotation processing until after
the other special sections have been cloned.

Fixes: dd590d4d57 ("objtool/klp: Introduce klp diff subcommand for diffing object files")
Acked-by: Song Liu <song@kernel.org>
Reviewed-by: Miroslav Benes <mbenes@suse.cz>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
This commit is contained in:
Josh Poimboeuf 2026-04-03 14:53:32 -07:00
parent 479ac5260e
commit 62a7a01fde

View File

@ -1437,6 +1437,7 @@ static int create_fake_symbols(struct elf *elf)
/* Keep a special section entry if it references an included function */
static bool should_keep_special_sym(struct elf *elf, struct symbol *sym)
{
bool annotate_insn = !strcmp(sym->sec->name, ".discard.annotate_insn");
struct reloc *reloc;
if (is_sec_sym(sym) || !sym->sec->rsec)
@ -1446,7 +1447,16 @@ static bool should_keep_special_sym(struct elf *elf, struct symbol *sym)
if (convert_reloc_sym(elf, reloc))
continue;
if (is_func_sym(reloc->sym) && reloc->sym->included)
if (!reloc->sym->clone || is_undef_sym(reloc->sym->clone))
continue;
/*
* Keep special section references to cloned functions.
* In some cases annotate_insn can also reference cloned alt
* replacement fake symbols; keep those references as well.
*/
if (is_func_sym(reloc->sym) ||
(annotate_insn && is_notype_sym(reloc->sym)))
return true;
}
@ -1590,15 +1600,28 @@ static int clone_special_section(struct elfs *e, struct section *patched_sec)
/* Extract only the needed bits from special sections */
static int clone_special_sections(struct elfs *e)
{
struct section *patched_sec;
struct section *sec, *annotate_insn = NULL;
for_each_sec(e->patched, patched_sec) {
if (is_special_section(patched_sec)) {
if (clone_special_section(e, patched_sec))
for_each_sec(e->patched, sec) {
if (is_special_section(sec)) {
if (!strcmp(sec->name, ".discard.annotate_insn")) {
annotate_insn = sec;
continue;
}
if (clone_special_section(e, sec))
return -1;
}
}
/*
* Do .discard.annotate_insn last, it can reference other special
* sections (alt replacements) so they need to be cloned first.
*/
if (annotate_insn) {
if (clone_special_section(e, annotate_insn))
return -1;
}
return 0;
}