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); 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 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 56*94553727SSong Liu int ENTRY(int x) { return helper(x, 4); } 57*94553727SSong Liu #endif 58