xref: /linux/tools/objtool/tests/generic/fixtures/thinlto_ambiguity.c (revision 5b6dca02b3e2254d2fd5706d76d7ab4610a67296)
1*94553727SSong Liu // SPDX-License-Identifier: GPL-2.0
2*94553727SSong Liu /*
3*94553727SSong Liu  * Three translation units linked with ThinLTO, two of which have a file-local
4*94553727SSong Liu  * helper of the same name.
5*94553727SSong Liu  *
6*94553727SSong Liu  * TU_C calls into both of the others, so ThinLTO imports entry_a and entry_b
7*94553727SSong Liu  * and with them the static helper each one calls.  A file-local symbol which
8*94553727SSong Liu  * has to become visible is renamed helper.llvm.<hash>, and the hash is content
9*94553727SSong Liu  * derived -- so the two helpers get different hashes from each other, and
10*94553727SSong Liu  * TU_A's gets a different one again after the patch changes it.  Only TU_A's
11*94553727SSong Liu  * changes: were both bodies to change, both would be cloned whichever way
12*94553727SSong Liu  * they were paired, and the pairing would not be observable.
13*94553727SSong Liu  *
14*94553727SSong Liu  * That leaves klp diff with two symbols in the original and two in the patched
15*94553727SSong Liu  * object, all four named differently, which have to be paired up correctly.
16*94553727SSong Liu  * Demangling alone gives "helper" for all of them; something else has to
17*94553727SSong Liu  * decide which is which.
18*94553727SSong Liu  *
19*94553727SSong Liu  * Only TU_A's helper changes.  That is what makes a wrong pairing observable:
20*94553727SSong Liu  * paired correctly, one helper is changed and the other is not, so exactly one
21*94553727SSong Liu  * is cloned.  Paired the wrong way round, both look changed -- or the wrong
22*94553727SSong Liu  * one does.  If both bodies changed the outcome would be the same either way
23*94553727SSong Liu  * and the test would prove nothing.
24*94553727SSong Liu  *
25*94553727SSong Liu  * BASE differs between the two so their bodies are not identical to begin
26*94553727SSong Liu  * with.
27*94553727SSong Liu  */
28*94553727SSong Liu 
29*94553727SSong Liu #if defined(TU_C)
30*94553727SSong Liu extern int entry_a(int x);
31*94553727SSong Liu extern int entry_b(int x);
glue(int x)32*94553727SSong Liu int glue(int x) { return entry_a(x) + entry_b(x + 1); }
33*94553727SSong Liu #else
34*94553727SSong Liu #ifdef TU_B
35*94553727SSong Liu #define ENTRY entry_b
36*94553727SSong Liu #define BASE 5
37*94553727SSong Liu #else
38*94553727SSong Liu #define ENTRY entry_a
39*94553727SSong Liu #define BASE 10
40*94553727SSong Liu static const char __modinfo[]
41*94553727SSong Liu 	__attribute__((section(".modinfo"), used, aligned(1))) = "\0name=vmlinux";
42*94553727SSong Liu #endif
helper(int x,int len)43*94553727SSong Liu static __attribute__((noinline)) int helper(int x, int len)
44*94553727SSong Liu {
45*94553727SSong Liu 	int sum = 0, i;
46*94553727SSong Liu 
47*94553727SSong Liu 	for (i = 0; i < len; i++)
48*94553727SSong Liu #if defined(PATCHED) && !defined(TU_B)
49*94553727SSong Liu 		sum += i * 2 + BASE;	/* only TU_A's helper changes */
50*94553727SSong Liu #else
51*94553727SSong Liu 		sum += i + BASE;
52*94553727SSong Liu #endif
53*94553727SSong Liu 	return sum + x;
54*94553727SSong Liu }
55*94553727SSong Liu 
ENTRY(int x)56*94553727SSong Liu int ENTRY(int x) { return helper(x, 4); }
57*94553727SSong Liu #endif
58