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
target(int x)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