summaryrefslogtreecommitdiff
path: root/tools/objtool/tests/generic/fixtures/thinlto_ambiguity.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/objtool/tests/generic/fixtures/thinlto_ambiguity.c')
-rw-r--r--tools/objtool/tests/generic/fixtures/thinlto_ambiguity.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/tools/objtool/tests/generic/fixtures/thinlto_ambiguity.c b/tools/objtool/tests/generic/fixtures/thinlto_ambiguity.c
new file mode 100644
index 000000000000..b88830f41a92
--- /dev/null
+++ b/tools/objtool/tests/generic/fixtures/thinlto_ambiguity.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Three translation units linked with ThinLTO, two of which have a file-local
+ * helper of the same name.
+ *
+ * TU_C calls into both of the others, so ThinLTO imports entry_a and entry_b
+ * and with them the static helper each one calls. A file-local symbol which
+ * has to become visible is renamed helper.llvm.<hash>, and the hash is content
+ * derived -- so the two helpers get different hashes from each other, and
+ * TU_A's gets a different one again after the patch changes it. Only TU_A's
+ * changes: were both bodies to change, both would be cloned whichever way
+ * they were paired, and the pairing would not be observable.
+ *
+ * That leaves klp diff with two symbols in the original and two in the patched
+ * object, all four named differently, which have to be paired up correctly.
+ * Demangling alone gives "helper" for all of them; something else has to
+ * decide which is which.
+ *
+ * Only TU_A's helper changes. That is what makes a wrong pairing observable:
+ * paired correctly, one helper is changed and the other is not, so exactly one
+ * is cloned. Paired the wrong way round, both look changed -- or the wrong
+ * one does. If both bodies changed the outcome would be the same either way
+ * and the test would prove nothing.
+ *
+ * BASE differs between the two so their bodies are not identical to begin
+ * with.
+ */
+
+#if defined(TU_C)
+extern int entry_a(int x);
+extern int entry_b(int x);
+int glue(int x) { return entry_a(x) + entry_b(x + 1); }
+#else
+#ifdef TU_B
+#define ENTRY entry_b
+#define BASE 5
+#else
+#define ENTRY entry_a
+#define BASE 10
+static const char __modinfo[]
+ __attribute__((section(".modinfo"), used, aligned(1))) = "\0name=vmlinux";
+#endif
+static __attribute__((noinline)) int helper(int x, int len)
+{
+ int sum = 0, i;
+
+ for (i = 0; i < len; i++)
+#if defined(PATCHED) && !defined(TU_B)
+ sum += i * 2 + BASE; /* only TU_A's helper changes */
+#else
+ sum += i + BASE;
+#endif
+ return sum + x;
+}
+
+int ENTRY(int x) { return helper(x, 4); }
+#endif