// SPDX-License-Identifier: GPL-2.0 /* * An x86 alternative whose replacement instruction carries a text annotation. * * The kernel does this wherever an ALTERNATIVE contains something objtool has * to be told about -- a retpoline-safe indirect branch, an intentionally * missing ENDBR -- so the .discard.annotate_insn entry references an address * inside .altinstr_replacement rather than inside a function. * * Two things make that awkward for klp diff, and both are why this fixture * exists. Replacement code has no real symbol: objtool invents a NOTYPE fake * symbol for it, so an annotation pointing there does not reference a FUNC. * And .discard.annotate_insn has to be cloned after .altinstructions, or the * replacement it names has no clone to point at yet. * * struct alt_instr is written out by hand as in empty_alternative.c: s32 * instr_offset, s32 repl_offset, u32 ft_flags, u8 instrlen, u8 replacementlen, * with an entsize so klp diff can find the entry boundaries. * .discard.annotate_insn entries are s32 offset, s32 type; type 2 is * ANNOTYPE_RETPOLINE_SAFE. * * The replacement label is global so the relocations name it rather than * .altinstr_replacement plus an addend, which klp diff cannot convert. It is * still NOTYPE, which is the shape that matters here. */ static const char __modinfo[] __attribute__((section(".modinfo"), used, aligned(1))) = "\0name=vmlinux"; int target(int x) { asm volatile( "661: nop\n\t" ".pushsection .altinstr_replacement, \"ax\"\n\t" ".globl target_repl\n\t" "target_repl:\n\t" " nop\n\t" /* The annotation lands inside the replacement. */ ".pushsection .discard.annotate_insn, \"M\", @progbits, 8\n\t" ".long target_repl - .\n\t" ".long 2\n\t" ".popsection\n\t" "target_repl_end:\n\t" ".popsection\n\t" ".pushsection .altinstructions, \"aM\", @progbits, 14\n\t" ".long 661b - .\n\t" ".long target_repl - .\n\t" ".long 0\n\t" ".byte 1\n\t" ".byte target_repl_end - target_repl\n\t" ".popsection\n\t"); #ifdef PATCHED return x + 2; #else return x + 1; #endif }