[lld] 1037f57 - [lld][elf] Warn if '*' pattern is used multiple times in version scripts (#102669)

via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 10 16:51:31 PDT 2024


Author: Igor Kudrin
Date: 2024-10-10T16:51:27-07:00
New Revision: 1037f577bd66ab03bc494120f024f2a52008e285

URL: https://github.com/llvm/llvm-project/commit/1037f577bd66ab03bc494120f024f2a52008e285
DIFF: https://github.com/llvm/llvm-project/commit/1037f577bd66ab03bc494120f024f2a52008e285.diff

LOG: [lld][elf] Warn if '*' pattern is used multiple times in version scripts (#102669)

If this pattern is used more than once in version script(s), only one
will have an effect, so it's probably a user error and can be diagnosed.

Added: 
    lld/test/ELF/version-script-warn.s

Modified: 
    lld/ELF/SymbolTable.cpp
    lld/test/ELF/version-script-reassign-glob.s

Removed: 
    


################################################################################
diff  --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index db8ee8f4d7b3bb..b9ef28f0436f88 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -309,13 +309,43 @@ void SymbolTable::scanVersionScript() {
 
   // Then, assign versions to "*". In GNU linkers they have lower priority than
   // other wildcards.
+  bool globalAsteriskFound = false;
+  bool localAsteriskFound = false;
+  bool asteriskReported = false;
+  auto assignAsterisk = [&](SymbolVersion &pat, VersionDefinition *ver,
+                            bool isLocal) {
+    // Avoid issuing a warning if both '--retain-symbol-file' and a version
+    // script with `global: *` are used.
+    //
+    // '--retain-symbol-file' adds a "*" pattern to
+    // 'config->versionDefinitions[VER_NDX_LOCAL].nonLocalPatterns', see
+    // 'readConfigs()' in 'Driver.cpp'. Note that it is not '.localPatterns',
+    // and may seem counterintuitive, but still works as expected. Here we can
+    // exploit that and skip analyzing the pattern added for this option.
+    if (!asteriskReported && (isLocal || ver->id > VER_NDX_LOCAL)) {
+      if ((isLocal && globalAsteriskFound) ||
+          (!isLocal && localAsteriskFound)) {
+        warn("wildcard pattern '*' is used for both 'local' and 'global' "
+             "scopes in version script");
+        asteriskReported = true;
+      } else if (!isLocal && globalAsteriskFound) {
+        warn("wildcard pattern '*' is used for multiple version definitions in "
+             "version script");
+        asteriskReported = true;
+      } else {
+        localAsteriskFound = isLocal;
+        globalAsteriskFound = !isLocal;
+      }
+    }
+    assignWildcard(pat, isLocal ? VER_NDX_LOCAL : ver->id, ver->name);
+  };
   for (VersionDefinition &v : llvm::reverse(ctx.arg.versionDefinitions)) {
     for (SymbolVersion &pat : v.nonLocalPatterns)
       if (pat.hasWildcard && pat.name == "*")
-        assignWildcard(pat, v.id, v.name);
+        assignAsterisk(pat, &v, false);
     for (SymbolVersion &pat : v.localPatterns)
       if (pat.hasWildcard && pat.name == "*")
-        assignWildcard(pat, VER_NDX_LOCAL, v.name);
+        assignAsterisk(pat, &v, true);
   }
 
   // Symbol themselves might know their versions because symbols

diff  --git a/lld/test/ELF/version-script-reassign-glob.s b/lld/test/ELF/version-script-reassign-glob.s
index 39d19a26fc4498..8de36467bd8ee6 100644
--- a/lld/test/ELF/version-script-reassign-glob.s
+++ b/lld/test/ELF/version-script-reassign-glob.s
@@ -10,7 +10,8 @@
 # RUN: llvm-readelf --dyn-syms %t.so | FileCheck --check-prefix=BAR %s
 
 # RUN: echo 'bar1 { *; }; bar2 { *; };' > %t2.ver
-# RUN: ld.lld --version-script %t2.ver %t.o -shared -o %t2.so --fatal-warnings
+# RUN: ld.lld --version-script %t2.ver %t.o -shared -o %t2.so 2>&1 | \
+# RUN:   FileCheck --check-prefix=DUPWARN %s
 # RUN: llvm-readelf --dyn-syms %t2.so | FileCheck --check-prefix=BAR2 %s
 
 ## If both a non-* glob and a * match, non-* wins.
@@ -21,6 +22,7 @@
 
 ## When there are multiple * patterns, the last wins.
 # BAR2: GLOBAL DEFAULT 7 foo@@bar2
+# DUPWARN: warning: wildcard pattern '*' is used for multiple version definitions in version script
 
 .globl foo
 foo:

diff  --git a/lld/test/ELF/version-script-warn.s b/lld/test/ELF/version-script-warn.s
new file mode 100644
index 00000000000000..9aba596165796b
--- /dev/null
+++ b/lld/test/ELF/version-script-warn.s
@@ -0,0 +1,35 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+
+# RUN: echo 'foo { *; }; bar { *; };' > %t.ver
+# RUN: ld.lld --version-script %t.ver %t.o -shared -o %t.so 2>&1 | \
+# RUN:   FileCheck --check-prefix=MULTVER %s
+
+# RUN: echo '{ global: *; local: *;};' > %t.ver
+# RUN: ld.lld --version-script %t.ver %t.o -shared -o %t.so 2>&1 | \
+# RUN:   FileCheck --check-prefix=LOCGLOB %s
+
+# RUN: echo 'V1 { global: *; }; V2 { local: *;};' > %t.ver
+# RUN: ld.lld --version-script %t.ver %t.o -shared -o %t.so 2>&1 | \
+# RUN:   FileCheck --check-prefix=LOCGLOB %s
+
+# RUN: echo 'V1 { local: *; }; V2 { global: *;};' > %t.ver
+# RUN: ld.lld --version-script %t.ver %t.o -shared -o %t.so 2>&1 | \
+# RUN:   FileCheck --check-prefix=LOCGLOB %s
+
+# RUN: echo 'V1 { local: *; }; V2 { local: *;};' > %t.ver
+# RUN: ld.lld --version-script %t.ver %t.o -shared -o %t.so --fatal-warnings
+
+## --retain-symbols-file uses the same internal infrastructure as the support
+## for version scripts. Do not show the warings if they both are used.
+# RUN: echo 'foo' > %t_retain.txt
+# RUN: echo '{ local: *; };' > %t_local.ver
+# RUN: echo '{ global: *; };' > %t_global.ver
+# RUN: ld.lld --retain-symbols-file=%t_retain.txt --version-script %t_local.ver %t.o -shared -o %t.so --fatal-warnings
+# RUN: ld.lld --retain-symbols-file=%t_retain.txt --version-script %t_global.ver %t.o -shared -o %t.so --fatal-warnings
+
+# MULTVER: warning: wildcard pattern '*' is used for multiple version definitions in version script
+# LOCGLOB: warning: wildcard pattern '*' is used for both 'local' and 'global' scopes in version script
+
+.globl foo
+foo:


        


More information about the llvm-commits mailing list