summaryrefslogtreecommitdiff
path: root/tools/objtool/tests/generic/fixtures/jump_label.c
blob: ecd3c06912af53a86b266965b55a096ada0d39fb (plain) (blame)
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
// SPDX-License-Identifier: GPL-2.0
/*
 * Static branch in a patched function.  The jump table entry is written out by
 * hand, mirroring JUMP_TABLE_ENTRY(), so the fixture builds without kernel
 * headers.  The key is an STT_OBJECT; anything else is ignored by
 * validate_special_section_klp_reloc().
 *
 * MODNAME selects whether the key is taken to belong to vmlinux or a module.
 *
 * NEW_KEY puts the whole static branch behind PATCHED, so the patch introduces
 * one where the original had none -- a different question from patching code
 * that already has a key, because the __jump_table entry itself is new.
 *
 * KEY_NAME renames the key.  Two names are special to
 * validate_special_section_klp_reloc(): a __tracepoint_* key and the
 * __UNIQUE_ID_ddebug_* one pr_debug() generates are both unsupported in a
 * module, but are disabled with a warning rather than rejected, because the
 * kernel is full of them and refusing outright would make ordinary functions
 * unpatchable.
 *
 * STATIC_KEY makes the key file-local.  That changes the shape of the
 * relocation rather than the meaning of the code: a reference to a static lands
 * on the section symbol plus an addend, so the key has to be resolved from the
 * section before it can be recognised as a key at all.
 */

#ifndef MODNAME
#define MODNAME "vmlinux"
#endif

#ifndef KEY_NAME
#define KEY_NAME klp_test_key
#endif

static const char __modinfo[]
	__attribute__((section(".modinfo"), used, aligned(1))) = "\0name=" MODNAME;

#ifdef STATIC_KEY
static long KEY_NAME;
#else
long KEY_NAME;
#endif

int target(int x)
{
	int r = x;

#if defined(NEW_KEY) && !defined(PATCHED)
	/* The original has no static branch at all. */
	return r + 1;
#else
	asm goto(
		"1:	nop\n\t"
		".pushsection	__jump_table, \"aw\"\n\t"
		".balign	8\n\t"
		"912:\n\t"
		".pushsection	.discard.annotate_data, \"M\", @progbits, 8\n\t"
		".long		912b - ., 1\n\t"
		".popsection\n\t"
		".long		1b - ., %l[l_yes] - .\n\t"
		".quad		%c0 - .\n\t"
		".popsection\n\t"
		: : "i" (&KEY_NAME) : : l_yes);

	r += 1;
	goto out;
l_yes:
	r += 2;
out:
#endif
#ifdef PATCHED
	return r + 100;
#else
	return r;
#endif
}