xref: /linux/tools/objtool/tests/generic/fixtures/checksum_data.c (revision 5b6dca02b3e2254d2fd5706d76d7ab4610a67296)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Data objects whose checksums must move for reasons the raw bytes do not
4  * show.
5  *
6  * checksum_update_object() hashes a data symbol's length and its bytes, and
7  * then walks its relocations: a reference into a string section contributes
8  * the string's *contents*, and any other reference contributes the target
9  * symbol's name and the adjusted addend.  So three changes that leave the
10  * object's own bytes identical still have to change its checksum:
11  *
12  * Each variant is selected by a -D on the patched build only, so the original
13  * is always the baseline:
14  *
15  *   WHICH_FUNC   the function pointer points somewhere else
16  *   WHICH_STR    the string pointer points at a different literal
17  *   STR_CONTENT  the string it points at is edited in place
18  *   WHICH_SLOT   the same array, at a different index: addend only
19  *   WHICH_PRIV   likewise, but a static, reached through its section symbol
20  *
21  * The last is the interesting one.  Nothing in the pointer changes -- same
22  * section, same offset -- so a checksum that hashed only the relocation and
23  * not what it referred to would call the object unchanged, and the patched
24  * kernel would keep the old string.
25  */
26 
27 static const char __modinfo[]
28 	__attribute__((section(".modinfo"), used, aligned(1))) = "\0name=vmlinux";
29 
30 int callee_a(int x);
31 int callee_b(int x);
callee_a(int x)32 int callee_a(int x) { return x + 1; }
callee_b(int x)33 int callee_b(int x) { return x + 2; }
34 
35 /*
36  * String *literals*, not named arrays.  The contents-hashing path keys on
37  * SHF_STRINGS, which the compiler sets on the mergeable .rodata.str1.1 a
38  * literal lands in and not on a named char[] given a section of its own.  A
39  * fixture using the latter exercises the ordinary name-and-addend path and
40  * reports nothing when the text changes.
41  */
42 #if defined(PATCHED) && defined(STR_CONTENT)
43 #define MESSAGE "edited"
44 #else
45 #define MESSAGE "original"
46 #endif
47 
48 /* A plain data object: only its own bytes decide the checksum. */
49 #if defined(PATCHED) && defined(PLAIN_VALUE)
50 int plain = 43;
51 #else
52 int plain = 42;
53 #endif
54 
55 /*
56  * A .bss object, where length is the only thing there is to hash: the section
57  * has no data, so the bytes are skipped and only sym->len distinguishes this
58  * from an object of another size.  An initialised array would not isolate it
59  * -- growing one changes the hashed bytes as well.
60  */
61 #if defined(PATCHED) && defined(LONGER)
62 char sized[4];
63 #else
64 char sized[2];
65 #endif
66 
67 /*
68  * A reference into the middle of an array: same target symbol, different
69  * addend.  Nothing else in the object changes, so this is the only way to see
70  * whether the addend is hashed at all.
71  */
72 int slots[4];
73 
74 /*
75  * A file-local array.  A reference to a static lands on its section symbol
76  * plus an offset, so the hash has to resolve that back to the underlying
77  * object before it has a name to hash at all -- a different code path from the
78  * global above, and one that silently contributes nothing when it fails.
79  */
80 static int priv_slots[4];
81 
82 struct desc {
83 	int (*fn)(int arg);
84 	const char *str;
85 	int *slot;
86 	int *priv;
87 };
88 
89 const struct desc descriptor = {
90 #if defined(PATCHED) && defined(WHICH_FUNC)
91 	.fn = callee_b,
92 #else
93 	.fn = callee_a,
94 #endif
95 #if defined(PATCHED) && defined(WHICH_STR)
96 	.str = "a different literal",
97 #else
98 	.str = MESSAGE,
99 #endif
100 #if defined(PATCHED) && defined(WHICH_SLOT)
101 	.slot = &slots[2],
102 #else
103 	.slot = &slots[1],
104 #endif
105 #if defined(PATCHED) && defined(WHICH_PRIV)
106 	.priv = &priv_slots[3],
107 #else
108 	.priv = &priv_slots[1],
109 #endif
110 };
111 
target(int x)112 int target(int x)
113 {
114 	return descriptor.fn(x) + plain + sized[0] + (int)descriptor.str[0] +
115 	       *descriptor.slot + *descriptor.priv;
116 }
117