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