Skip to content

Conversation

@igorkudrin
Copy link
Collaborator

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.

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.
@igorkudrin igorkudrin requested a review from MaskRay August 9, 2024 19:46
@llvmbot llvmbot added the lld label Aug 9, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 9, 2024

@llvm/pr-subscribers-lld

@llvm/pr-subscribers-lld-elf

Author: Igor Kudrin (igorkudrin)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/102669.diff

3 Files Affected:

  • (modified) lld/ELF/SymbolTable.cpp (+33-2)
  • (modified) lld/test/ELF/version-script-reassign-glob.s (+3-1)
  • (added) lld/test/ELF/version-script-warn.s (+35)
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index 258a78ab40bb57..f7465cd5d097fc 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -311,13 +311,44 @@ void SymbolTable::scanVersionScript() {
 
   // Then, assign versions to "*". In GNU linkers they have lower priority than
   // other wildcards.
+  bool globalAsteriskWildcardFound = false;
+  bool localAsteriskWildcardFound = false;
+  bool asteriskWildcardReported = false;
+  auto assignAsteriskWildcard = [&](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 '.nonLocalPatterns', not
+    // '.localPatterns', which may seem counterintuitive, but still works as
+    // expected. Here we can exploit that and skip analyzing the pattern added
+    // for this option.
+    if (!asteriskWildcardReported && (isLocal || ver->id > VER_NDX_LOCAL)) {
+      if ((isLocal && globalAsteriskWildcardFound) ||
+          (!isLocal && localAsteriskWildcardFound)) {
+        warn("Wildcard pattern '*' is used for both 'local' and 'global' "
+             "scopes in version script");
+        asteriskWildcardReported = true;
+      } else if (!isLocal && globalAsteriskWildcardFound) {
+        warn("Wildcard pattern '*' is used for multiple version definitions in "
+             "version script");
+        asteriskWildcardReported = true;
+      } else {
+        localAsteriskWildcardFound = isLocal;
+        globalAsteriskWildcardFound = !isLocal;
+      }
+    }
+    assignWildcard(pat, isLocal ? VER_NDX_LOCAL : ver->id, ver->name);
+  };
   for (VersionDefinition &v : llvm::reverse(config->versionDefinitions)) {
     for (SymbolVersion &pat : v.nonLocalPatterns)
       if (pat.hasWildcard && pat.name == "*")
-        assignWildcard(pat, v.id, v.name);
+        assignAsteriskWildcard(pat, &v, false);
     for (SymbolVersion &pat : v.localPatterns)
       if (pat.hasWildcard && pat.name == "*")
-        assignWildcard(pat, VER_NDX_LOCAL, v.name);
+        assignAsteriskWildcard(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..6470b67b5a1667 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..43ed97d04eeea3
--- /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:

if (!asteriskWildcardReported && (isLocal || ver->id > VER_NDX_LOCAL)) {
if ((isLocal && globalAsteriskWildcardFound) ||
(!isLocal && localAsteriskWildcardFound)) {
warn("Wildcard pattern '*' is used for both 'local' and 'global' "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't capitalize warn/error messages

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Fixed.


// Then, assign versions to "*". In GNU linkers they have lower priority than
// other wildcards.
bool globalAsteriskWildcardFound = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These variables might look mouthful as asterisk is a wildcard character.
Perhaps AsteriskWildcard => Asterisk

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@igorkudrin
Copy link
Collaborator Author

Ping

1 similar comment
@igorkudrin
Copy link
Collaborator Author

Ping

@igorkudrin
Copy link
Collaborator Author

Ping

Copy link
Member

@MaskRay MaskRay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry. This is early in my /pulls/review-requested queue and I haven't noticed it...

@igorkudrin
Copy link
Collaborator Author

Thanks!

@igorkudrin igorkudrin merged commit 1037f57 into llvm:main Oct 10, 2024
8 checks passed
@igorkudrin igorkudrin deleted the lld-version-scripts-asterisk-pattern-warn branch October 10, 2024 23:51
DanielCChen pushed a commit to DanielCChen/llvm-project that referenced this pull request Oct 16, 2024
…pts (llvm#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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants