Repository: davidlattimore/wild (rust)

Issue:
Duplicate symbols regression with recent main branch
I've tried rebuilding Rust with the latest main branch, but it regressed and spews out hundreds of duplicate symbols, like here: https://gist.github.com/mati865/312e2a7d2ee0b6f38669315a64db4e6d

Reproduces only when LLVM is built alongside Rust, by editing `config.toml` to:
```
[llvm]
download-ci-llvm = false
```
And running: `PATH=~/Projects/wild:$PATH ./x.py b`

EDIT: Reverting https://github.com/davidlattimore/wild/pull/591 solves the build issue.

Pull request:
Don't emit duplicate symbol error on STB_GNU_UNIQUE
Fixes #598

Patch:
diff --git a/libwild/src/symbol_db.rs b/libwild/src/symbol_db.rs
index 7344650..bb82f49 100644
--- a/libwild/src/symbol_db.rs
+++ b/libwild/src/symbol_db.rs
@@ -542,6 +542,8 @@ impl<'data> SymbolDb<'data> {
                 SymbolStrength::Weak
             } else if obj_symbol.is_common(e) {
                 SymbolStrength::Common(obj_symbol.st_size(e))
+            } else if obj_symbol.st_bind() == object::elf::STB_GNU_UNIQUE {
+                SymbolStrength::GnuUnique
             } else {
                 SymbolStrength::Strong
             }
@@ -750,6 +752,9 @@ enum SymbolStrength {
     /// The object weakly defines the symbol.
     Weak,
 
+    /// The object uses STB_GNU_UNIQUE binding.
+    GnuUnique,
+
     /// The object strongly defines the symbol.
     Strong,
 


Test patch:
diff --git a/wild/tests/integration_tests.rs b/wild/tests/integration_tests.rs
index 5419ecd..1f72089 100644
--- a/wild/tests/integration_tests.rs
+++ b/wild/tests/integration_tests.rs
@@ -2154,6 +2154,7 @@ fn integration_test(
         "eh_frame.c",
         "trivial_asm.s",
         "non-alloc.s",
+        "gnu-unique.c",
         "symbol-versions.c",
         "copy-relocations.c",
         "force-undefined.c",
diff --git a/wild/tests/sources/gnu-unique-1.cc b/wild/tests/sources/gnu-unique-1.cc
new file mode 100644
index 0000000..48d3c29
--- /dev/null
+++ b/wild/tests/sources/gnu-unique-1.cc
@@ -0,0 +1,11 @@
+#include "gnu-unique.h"
+
+typedef int(*get_int_fn_t)(int);
+
+extern "C" {
+
+get_int_fn_t get_fn1(void) {
+    return get_value<int>;
+}
+
+}
diff --git a/wild/tests/sources/gnu-unique-2.cc b/wild/tests/sources/gnu-unique-2.cc
new file mode 100644
index 0000000..1c72fb7
--- /dev/null
+++ b/wild/tests/sources/gnu-unique-2.cc
@@ -0,0 +1,11 @@
+#include "gnu-unique.h"
+
+typedef int(*get_int_fn_t)(int);
+
+extern "C" {
+
+get_int_fn_t get_fn2(void) {
+    return get_value<int>;
+}
+
+}
diff --git a/wild/tests/sources/gnu-unique.c b/wild/tests/sources/gnu-unique.c
new file mode 100644
index 0000000..def9c33
--- /dev/null
+++ b/wild/tests/sources/gnu-unique.c
@@ -0,0 +1,27 @@
+//#Object:exit.c
+//#Object:gnu-unique-1.cc
+//#Object:gnu-unique-2.cc
+
+#include "exit.h"
+
+typedef int(*get_int_fn_t)(int);
+
+// Each of these functions instantiates the same template with the same type. The template contains
+// a static variable that is incremented each time it's called. GCC will emit this static as
+// STB_GNU_UNIQUE in order to ensure that there's only a single instance of it.
+get_int_fn_t get_fn1(void);
+get_int_fn_t get_fn2(void);
+
+void _start(void) {
+    // 10 + 1 == 1
+    if (get_fn1()(10) != 11) {
+        exit_syscall(11);
+    }
+
+    // 10 + 2 = 17
+    if (get_fn2()(15) != 17) {
+        exit_syscall(12);
+    }
+
+    exit_syscall(42);
+}
diff --git a/wild/tests/sources/gnu-unique.h b/wild/tests/sources/gnu-unique.h
new file mode 100644
index 0000000..dcbaffb
--- /dev/null
+++ b/wild/tests/sources/gnu-unique.h
@@ -0,0 +1,7 @@
+template<typename T>
+T get_value(T v) {
+    // This static variable inside a template is what causes GCC to emit a symbol as UNIQUE.
+    static T def = 0;
+    def++;
+    return v + def;
+}