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