xref: /linux/tools/objtool/tests/x86/fixtures/checksum_alt.c (revision 5b6dca02b3e2254d2fd5706d76d7ab4610a67296)
1*32b2cf11SSong Liu // SPDX-License-Identifier: GPL-2.0
2*32b2cf11SSong Liu /*
3*32b2cf11SSong Liu  * An x86 alternative whose replacement code is part of the patched function's
4*32b2cf11SSong Liu  * checksum.
5*32b2cf11SSong Liu  *
6*32b2cf11SSong Liu  * checksum_update_insn() walks insn->alts after hashing the instruction
7*32b2cf11SSong Liu  * itself, hashing the alternative's type and, when the replacement forms a
8*32b2cf11SSong Liu  * group, its feature number and every instruction in it.  So editing only the
9*32b2cf11SSong Liu  * replacement -- code the CPU may or may not ever run -- has to move the
10*32b2cf11SSong Liu  * function's checksum.
11*32b2cf11SSong Liu  *
12*32b2cf11SSong Liu  * It is reached through objtool's own alternative handling, so the object has
13*32b2cf11SSong Liu  * to go through the check pass first: insn->alts is built there, not by the
14*32b2cf11SSong Liu  * compiler.
15*32b2cf11SSong Liu  *
16*32b2cf11SSong Liu  * struct alt_instr is written out by hand as in empty_alternative.c: s32
17*32b2cf11SSong Liu  * instr_offset, s32 repl_offset, u32 ft_flags, u8 instrlen, u8 replacementlen.
18*32b2cf11SSong Liu  *
19*32b2cf11SSong Liu  * Variants, applied to the patched build only:
20*32b2cf11SSong Liu  *
21*32b2cf11SSong Liu  *   ALT_REPL     the replacement instruction changes; the original does not
22*32b2cf11SSong Liu  *   ALT_FEATURE  the feature number changes; no code changes at all
23*32b2cf11SSong Liu  */
24*32b2cf11SSong Liu 
25*32b2cf11SSong Liu static const char __modinfo[]
26*32b2cf11SSong Liu 	__attribute__((section(".modinfo"), used, aligned(1))) = "\0name=vmlinux";
27*32b2cf11SSong Liu 
28*32b2cf11SSong Liu /*
29*32b2cf11SSong Liu  * Both spellings are two bytes, because a replacement may not be longer than
30*32b2cf11SSong Liu  * the instruction it replaces: "xchg %ax, %ax" is 66 90 and two nops are
31*32b2cf11SSong Liu  * 90 90.  The original below is padded to match.
32*32b2cf11SSong Liu  */
33*32b2cf11SSong Liu #if defined(PATCHED) && defined(ALT_REPL)
34*32b2cf11SSong Liu #define REPL_INSN "	nop\n\t	nop\n\t"
35*32b2cf11SSong Liu #else
36*32b2cf11SSong Liu #define REPL_INSN "	xchg %ax, %ax\n\t"
37*32b2cf11SSong Liu #endif
38*32b2cf11SSong Liu 
39*32b2cf11SSong Liu #if defined(PATCHED) && defined(ALT_FEATURE)
40*32b2cf11SSong Liu #define FEATURE "7"
41*32b2cf11SSong Liu #else
42*32b2cf11SSong Liu #define FEATURE "3"
43*32b2cf11SSong Liu #endif
44*32b2cf11SSong Liu 
target(int x)45*32b2cf11SSong Liu int target(int x)
46*32b2cf11SSong Liu {
47*32b2cf11SSong Liu 	asm volatile(
48*32b2cf11SSong Liu 		"661:	nop\n\t"
49*32b2cf11SSong Liu 		"	nop\n\t"
50*32b2cf11SSong Liu 		"662:\n\t"
51*32b2cf11SSong Liu 		".pushsection .altinstr_replacement, \"ax\"\n\t"
52*32b2cf11SSong Liu 		".globl target_repl\n\t"
53*32b2cf11SSong Liu 		"target_repl:\n\t"
54*32b2cf11SSong Liu 		REPL_INSN
55*32b2cf11SSong Liu 		"target_repl_end:\n\t"
56*32b2cf11SSong Liu 		".popsection\n\t"
57*32b2cf11SSong Liu 		".pushsection .altinstructions, \"aM\", @progbits, 14\n\t"
58*32b2cf11SSong Liu 		".long 661b - .\n\t"
59*32b2cf11SSong Liu 		".long target_repl - .\n\t"
60*32b2cf11SSong Liu 		".long " FEATURE "\n\t"
61*32b2cf11SSong Liu 		".byte 662b - 661b\n\t"
62*32b2cf11SSong Liu 		".byte target_repl_end - target_repl\n\t"
63*32b2cf11SSong Liu 		".popsection\n\t");
64*32b2cf11SSong Liu 
65*32b2cf11SSong Liu 	return x + 1;
66*32b2cf11SSong Liu }
67