xref: /linux/tools/objtool/tests/x86/fixtures/empty_alternative.c (revision 5b6dca02b3e2254d2fd5706d76d7ab4610a67296)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * An x86 alternative with an empty replacement, as the second entry of
4  * ALTERNATIVE_2("orig", "repl", ft1, "", ft2) produces.  Its replacement
5  * offset still gets a relocation, but the label it points at is the end of the
6  * previous replacement, which is also where the *next* one begins -- here,
7  * neighbor()'s.  The value is meaningless; it is only ever used with a length
8  * of zero.
9  *
10  * struct alt_instr is written out by hand so the fixture builds without kernel
11  * headers: s32 instr_offset, s32 repl_offset, u32 ft_flags, u8 instrlen,
12  * u8 replacementlen.  The section carries an entsize because klp diff needs
13  * either that or an ANNOTATE_DATA_SPECIAL annotation to find entry boundaries.
14  *
15  * The replacement labels are global so the relocations name them rather than
16  * .altinstr_replacement plus an addend.
17  */
18 
19 static const char __modinfo[]
20 	__attribute__((section(".modinfo"), used, aligned(1))) = "\0name=vmlinux";
21 
22 extern int neighbor_only(int x);
23 
target(int x)24 int target(int x)
25 {
26 	asm volatile(
27 		"661:	nop\n\t"
28 		".pushsection .altinstr_replacement, \"ax\"\n\t"
29 		".globl target_repl\n\t"
30 		"target_repl:\n\t"
31 		"	nop\n\t"
32 		"target_repl_end:\n\t"
33 		".popsection\n\t"
34 		".pushsection .altinstructions, \"aM\", @progbits, 14\n\t"
35 		/* a real replacement */
36 		".long 661b - .\n\t"
37 		".long target_repl - .\n\t"
38 		".long 0\n\t"
39 		".byte 1\n\t"
40 		".byte target_repl_end - target_repl\n\t"
41 		/* an empty one, pointing at neighbor()'s replacement */
42 		".long 661b - .\n\t"
43 		".long neighbor_repl - .\n\t"
44 		".long 0\n\t"
45 		".byte 1\n\t"
46 		".byte 0\n\t"
47 		".popsection\n\t");
48 #ifdef PATCHED
49 	return x + 2;
50 #else
51 	return x + 1;
52 #endif
53 }
54 
55 /*
56  * Unrelated, unpatched, and referencing a symbol nothing else does, so that
57  * dragging its replacement in is visible.
58  */
neighbor(int x)59 int neighbor(int x)
60 {
61 	asm volatile(
62 		"771:	nop\n\t"
63 		".pushsection .altinstr_replacement, \"ax\"\n\t"
64 		".globl neighbor_repl\n\t"
65 		"neighbor_repl:\n\t"
66 		"	call neighbor_only\n\t"
67 		"neighbor_repl_end:\n\t"
68 		".popsection\n\t"
69 		".pushsection .altinstructions, \"aM\", @progbits, 14\n\t"
70 		".long 771b - .\n\t"
71 		".long neighbor_repl - .\n\t"
72 		".long 0\n\t"
73 		".byte 1\n\t"
74 		".byte neighbor_repl_end - neighbor_repl\n\t"
75 		".popsection\n\t");
76 	return x;
77 }
78