[llvm] [bolt] Resolve duplicated symbols name through versioning (PR #203223)

Alexey Moksyakov via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 11 02:49:51 PDT 2026


https://github.com/yavtuk updated https://github.com/llvm/llvm-project/pull/203223

>From 430d9383285f07d4f1615ceb079091cd7569046e Mon Sep 17 00:00:00 2001
From: yavtuk <yavtuk at ya.ru>
Date: Thu, 11 Jun 2026 12:33:40 +0300
Subject: [PATCH] [bolt] Resolve duplicated symbols name through versioning

---
 bolt/lib/Rewrite/RewriteInstance.cpp | 33 ++++++++++++++++++++-
 bolt/test/duplicate_symbols.test     | 44 ++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+), 1 deletion(-)
 create mode 100644 bolt/test/duplicate_symbols.test

diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 9364e32939982..f4898b01a2528 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -933,6 +933,34 @@ void RewriteInstance::discoverFileObjects() {
 
     return false;
   };
+
+  // read dynamic symbols name and version
+  DenseMap<uint64_t, std::string> DynSymNames;
+  Expected<std::vector<VersionEntry>> SymbolVersionOrErr =
+      InputFile->readDynsymVersions();
+  if (SymbolVersionOrErr && !SymbolVersionOrErr->empty()) {
+    ArrayRef<VersionEntry> SymbolVersions = *SymbolVersionOrErr;
+    for (const SymbolRef &Symbol : InputFile->getDynamicSymbolIterators()) {
+      const uint64_t SymAddress = cantFail(Symbol.getAddress());
+      if (!isSymbolInMemory(Symbol) || !SymAddress)
+        continue;
+      Expected<StringRef> NameOrError = Symbol.getName();
+      if (!NameOrError) {
+        consumeError(NameOrError.takeError());
+        continue;
+      }
+      StringRef SymbolName = *NameOrError;
+      if (SymbolName.empty())
+        continue;
+      const VersionEntry &Ver =
+          SymbolVersions[Symbol.getRawDataRefImpl().d.b - 1];
+      if (Ver.Name.empty())
+        continue;
+      DynSymNames[SymAddress] =
+          SymbolName.str() + (Ver.IsVerDef ? "@@" : "@") + Ver.Name;
+    }
+  }
+
   for (const SymbolRef &Symbol : InputFile->symbols())
     if (isSymbolInMemory(Symbol)) {
       SymbolInfo SymInfo{cantFail(Symbol.getAddress()), Symbol};
@@ -1034,7 +1062,10 @@ void RewriteInstance::discoverFileObjects() {
     if (SymbolType == SymbolRef::ST_File)
       continue;
 
-    StringRef SymName = cantFail(Symbol.getName(), "cannot get symbol name");
+    StringRef SymName =
+        DynSymNames.find(SymbolAddress) != DynSymNames.end()
+            ? DynSymNames[SymbolAddress]
+            : cantFail(Symbol.getName(), "cannot get symbol name");
     if (SymbolAddress == 0) {
       if (opts::Verbosity >= 1 && SymbolType == SymbolRef::ST_Function)
         BC->errs() << "BOLT-WARNING: function with 0 address seen\n";
diff --git a/bolt/test/duplicate_symbols.test b/bolt/test/duplicate_symbols.test
new file mode 100644
index 0000000000000..0798861b5a923
--- /dev/null
+++ b/bolt/test/duplicate_symbols.test
@@ -0,0 +1,44 @@
+## Verify that BOLT can correctly process binaries with duplicate symbols.
+
+# REQUIRES: system-linux
+
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t.o
+
+## Shared library with the duplicate symbol "foo", which requires a version script.
+# RUN: echo "VERS_1 { global: foo; }; VERS_2 { global: foo; } VERS_1;" > %t.map
+# RUN: ld.lld %t.o -o %t.so -shared --version-script %t.map
+# RUN: llvm-bolt %t.so -o %t.so.bolt 2>&1 | FileCheck %s --check-prefix=CHECK-SHARED
+
+# CHECK-SHARED-NOT: bad input binary, global symbol "foo" is not unique
+
+## Main executable with the duplicate symbol "foo",
+## linked from a static object/archive without needing a version script.
+# RUN: ld.lld %t.o -o %t.exe
+# RUN: not llvm-bolt %t.exe -o %t.exe.bolt 2>&1 | FileCheck %s  --check-prefix=CHECK-STATIC
+
+# CHECK-STATIC: BOLT-ERROR: bad input binary, global symbol "foo" is not unique
+
+.text
+.globl _start
+.type _start, @function
+_start:
+  call foo_v1
+  call foo_v2
+  ret
+.size _start, .-_start
+
+.globl foo_v1
+.type foo_v1, @function
+foo_v1:
+  nop
+  nop
+.size foo_v1, .-foo_v1
+
+.globl foo_v2
+.type foo_v2, @function
+foo_v2:
+  ret
+.size foo_v2, .-foo_v2
+
+.symver foo_v1, foo at VERS_1
+.symver foo_v2, foo@@VERS_2
\ No newline at end of file



More information about the llvm-commits mailing list