1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * An x86 alternative whose replacement instruction carries a text annotation. 4 * 5 * The kernel does this wherever an ALTERNATIVE contains something objtool has 6 * to be told about -- a retpoline-safe indirect branch, an intentionally 7 * missing ENDBR -- so the .discard.annotate_insn entry references an address 8 * inside .altinstr_replacement rather than inside a function. 9 * 10 * Two things make that awkward for klp diff, and both are why this fixture 11 * exists. Replacement code has no real symbol: objtool invents a NOTYPE fake 12 * symbol for it, so an annotation pointing there does not reference a FUNC. 13 * And .discard.annotate_insn has to be cloned after .altinstructions, or the 14 * replacement it names has no clone to point at yet. 15 * 16 * struct alt_instr is written out by hand as in empty_alternative.c: s32 17 * instr_offset, s32 repl_offset, u32 ft_flags, u8 instrlen, u8 replacementlen, 18 * with an entsize so klp diff can find the entry boundaries. 19 * .discard.annotate_insn entries are s32 offset, s32 type; type 2 is 20 * ANNOTYPE_RETPOLINE_SAFE. 21 * 22 * The replacement label is global so the relocations name it rather than 23 * .altinstr_replacement plus an addend, which klp diff cannot convert. It is 24 * still NOTYPE, which is the shape that matters here. 25 */ 26 27 static const char __modinfo[] 28 __attribute__((section(".modinfo"), used, aligned(1))) = "\0name=vmlinux"; 29 30 int target(int x) 31 { 32 asm volatile( 33 "661: nop\n\t" 34 ".pushsection .altinstr_replacement, \"ax\"\n\t" 35 ".globl target_repl\n\t" 36 "target_repl:\n\t" 37 " nop\n\t" 38 /* The annotation lands inside the replacement. */ 39 ".pushsection .discard.annotate_insn, \"M\", @progbits, 8\n\t" 40 ".long target_repl - .\n\t" 41 ".long 2\n\t" 42 ".popsection\n\t" 43 "target_repl_end:\n\t" 44 ".popsection\n\t" 45 ".pushsection .altinstructions, \"aM\", @progbits, 14\n\t" 46 ".long 661b - .\n\t" 47 ".long target_repl - .\n\t" 48 ".long 0\n\t" 49 ".byte 1\n\t" 50 ".byte target_repl_end - target_repl\n\t" 51 ".popsection\n\t"); 52 #ifdef PATCHED 53 return x + 2; 54 #else 55 return x + 1; 56 #endif 57 } 58