From 9e388c22a69365293538aa45f211a922ccb9c9c7 Mon Sep 17 00:00:00 2001 From: Joe Lawrence Date: Tue, 8 Sep 2026 18:12:59 -0400 Subject: [PATCH] create-diff-object: include __ftr_alt_* when regenerating __ftr_fixup When a changed ppc64le function is referenced by a kept __ftr_fixup group, create-diff-object must also include the corresponding __ftr_alt_* section data. kpatch_regenerate_special_section() currently only sets rela->sym->include = 1, which does not migrate STT_SECTION companions and leaves UND relocs in .rela__ftr_fixup: ld: final link failed: bad value Call kpatch_include_symbol() instead, matching the similar .altinstr_replacement fix in 13b00146715c ("kpatch-build: ensure that .altinstr_replacement section is included"). Also exempt __ftr_fixup -> __ftr_alt_* relocations from the out-of-range relocation check. Those addends are linker inputs for fixup-entry offsets, not pointers into the alt section. Closes: 1522 ("ppc64le __ftr_fixup / __ftr_alt_97 sections causing bad final link") Signed-off-by: Joe Lawrence --- kpatch-build/create-diff-object.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 051f8e82..3d01e71b 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -2937,7 +2937,7 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, rela->offset -= src_offset - dest_offset; rela->rela.r_offset = rela->offset; - rela->sym->include = 1; + kpatch_include_symbol(rela->sym); if (!strcmp(special->name, ".fixup")) kpatch_update_ex_table_addend(kelf, special, @@ -3079,6 +3079,20 @@ static void kpatch_regenerate_orc_sections(struct kpatch_elf *kelf) ip_sec->data->d_size = dest_idx * ORC_IP_PTR_SIZE; } +static bool is_ftr_alt_fixup_reloc(struct section *relasec, struct rela *rela) +{ + if (!relasec->base) + return false; + + if (strncmp(relasec->base->name, "__ftr_fixup", 11) && + strncmp(relasec->base->name, "__mmu_ftr_fixup", 15) && + strncmp(relasec->base->name, "__fw_ftr_fixup", 14)) + return false; + + return rela->sym->type == STT_SECTION && + !strncmp(rela->sym->name, "__ftr_alt_", 10); +} + static void kpatch_check_relocations(struct kpatch_elf *kelf) { struct rela *rela; @@ -3092,6 +3106,8 @@ static void kpatch_check_relocations(struct kpatch_elf *kelf) list_for_each_entry(rela, &relasec->relas, list) { if (!rela->sym->sec) continue; + if (is_ftr_alt_fixup_reloc(relasec, rela)) + continue; sec_size = rela->sym->sec->data->d_size; sec_off = (long)rela->sym->sym.st_value +