From: George Guo <[email protected]> With -mannotate-tablejump, LoongArch compilers emit a .discard.tablejump_annotate section. Each entry is a pair of 8-byte words: the address of a jump instruction and the address of its jump table. objtool reads these pairs to find switch jump tables when decoding.
klp-diff creates one fake symbol per 8-byte word and clones a word only if should_keep_special_sym() accepts it. The default rule keeps a word only if it references a function that was cloned into the output module. The instruction-side word references the function and is kept. The table-side word references the jump table via its .rodata section symbol, which is not a function symbol, so it is dropped. The cloned annotate section then holds only instruction-side words, compacted together. The pairing is destroyed. Parsing the malformed section crashes objtool on the patch module and no .ko is produced: Building patch module: livepatch-shadow-newpid.ko livepatch-shadow-newpid.o: error: SIGSEGV: objtool crash! Keep all .discard.tablejump_annotate words whose referenced symbol has been cloned. Reproduced with the shadow-newpid test, which patches proc_pid_status(). That function contains two switch jump tables. Before, klp-diff clones only the instruction-side words: DEBUG: vmlinux.o: _discard_tablejump_annotate_57441 [+DATA] DEBUG: vmlinux.o: .discard.tablejump_annotate+0x0: proc_pid_status+0xc70 [FUNC GLOBAL] DEBUG: vmlinux.o: _discard_tablejump_annotate_57443 [+DATA] DEBUG: vmlinux.o: .discard.tablejump_annotate+0x8: proc_pid_status+0xd2c [FUNC GLOBAL] After, the full pairs are kept, including the .rodata table words: DEBUG: vmlinux.o: _discard_tablejump_annotate_57441 [+DATA] DEBUG: vmlinux.o: .discard.tablejump_annotate+0x0: proc_pid_status+0xc70 [FUNC GLOBAL] DEBUG: vmlinux.o: _discard_tablejump_annotate_57442 [+DATA] DEBUG: vmlinux.o: .discard.tablejump_annotate+0x8: .rodata.proc_pid_status+0x0 [SECTION] DEBUG: vmlinux.o: _discard_tablejump_annotate_57443 [+DATA] DEBUG: vmlinux.o: .discard.tablejump_annotate+0x10: proc_pid_status+0xd2c [FUNC GLOBAL] DEBUG: vmlinux.o: _discard_tablejump_annotate_57444 [+DATA] DEBUG: vmlinux.o: .discard.tablejump_annotate+0x18: .rodata.proc_pid_status+0x80 [SECTION] and the patch module builds. Co-developed-by: Kexin Liu <[email protected]> Signed-off-by: Kexin Liu <[email protected]> Signed-off-by: George Guo <[email protected]> --- tools/objtool/klp-diff.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c index 92cf0fc3ff2f..f151ffc71184 100644 --- a/tools/objtool/klp-diff.c +++ b/tools/objtool/klp-diff.c @@ -1956,6 +1956,7 @@ static int create_fake_symbols(struct elf *elf) static bool should_keep_special_sym(struct elf *elf, struct symbol *sym) { bool annotate_insn = !strcmp(sym->sec->name, ".discard.annotate_insn"); + bool tablejump_annotate = !strcmp(sym->sec->name, ".discard.tablejump_annotate"); struct reloc *reloc; if (is_sec_sym(sym) || !sym->sec->rsec) @@ -1968,6 +1969,16 @@ static bool should_keep_special_sym(struct elf *elf, struct symbol *sym) if (!reloc->sym->clone || is_undef_sym(reloc->sym->clone)) continue; + /* + * .discard.tablejump_annotate (LoongArch -mannotate-tablejump) + * holds pairs of words: a jump instruction and its jump table. + * The table word references the table via its .rodata section + * symbol, which the is_func_sym() rule below would drop, + * breaking the pairing. Keep both words of each entry. + */ + if (tablejump_annotate) + return true; + /* * Keep special section references to cloned functions. * In some cases annotate_insn can also reference cloned alt -- 2.53.0

