xref: /linux/tools/objtool/tests/generic/fixtures/checksum_position.c (revision 12d5fc96ebbb3b948861805b32a4c3a96105ccd9)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * A function whose position in the section changes between the two builds,
4  * without the function itself changing.
5  *
6  * target() calls callee() twice, and a call within the same section needs no
7  * relocation: the displacement is in the instruction.  It is that displacement
8  * which moves, and hashing those bytes makes the checksum move with it.  Both
9  * must therefore share a section, which is why the test passes
10  * -fno-function-sections.
11  *
12  * What has to change is the distance between the two, and PATCHED changes it
13  * by aligning them rather than by inserting a function between them.  Where a
14  * compiler puts an added function is its own business: gcc emits these in
15  * source order, so a function written between callee() and target() separates
16  * them, but clang emits target() immediately before callee() whatever the
17  * source says, and an added function lands ahead of both.  That moves target()
18  * without moving it relative to callee(), the displacement comes out identical
19  * in both builds, and the test passes without having asked anything.
20  *
21  * Alignment moves the functions apart on both, and moves neither function's
22  * own instructions -- which is exactly the distinction under test.
23  */
24 
25 #ifdef PATCHED
26 #define MOVED	__attribute__((aligned(64)))
27 #else
28 #define MOVED
29 #endif
30 
31 static const char __modinfo[]
32 	__attribute__((section(".modinfo"), used, aligned(1))) = "\0name=vmlinux";
33 
34 __attribute__((noinline)) MOVED static int callee(int x)
35 {
36 	return x * 5 + 1;
37 }
38 
39 __attribute__((noinline)) MOVED int target(int x)
40 {
41 	return callee(x) + callee(x + 1);
42 }
43