[lld] 387c965 - [ELF,test] Cover wildcard precedence in version scripts and dynamic lists (#223195)

via llvm-commits llvm-commits at lists.llvm.org
Sat Sep 12 18:55:32 PDT 2026


Author: Fangrui Song
Date: 2026-09-12T18:55:27-07:00
New Revision: 387c965bb013d14dbcee52098e714c27d6f98249

URL: https://github.com/llvm/llvm-project/commit/387c965bb013d14dbcee52098e714c27d6f98249
DIFF: https://github.com/llvm/llvm-project/commit/387c965bb013d14dbcee52098e714c27d6f98249.diff

LOG: [ELF,test] Cover wildcard precedence in version scripts and dynamic lists (#223195)

version-script-wildcard-precedence.s, renamed from
version-script-reassign-glob.s, covers more cases.

dynamic-list-glob.s absorbs dynamic-list-cpp.s and adds an extern "C++"
wildcard, which had no --dynamic-list coverage.

Added: 
    lld/test/ELF/version-script-wildcard-precedence.s

Modified: 
    lld/test/ELF/dynamic-list-glob.s

Removed: 
    lld/test/ELF/dynamic-list-cpp.s
    lld/test/ELF/version-script-reassign-glob.s


################################################################################
diff  --git a/lld/test/ELF/dynamic-list-cpp.s b/lld/test/ELF/dynamic-list-cpp.s
deleted file mode 100644
index 05f11e0079d34..0000000000000
--- a/lld/test/ELF/dynamic-list-cpp.s
+++ /dev/null
@@ -1,18 +0,0 @@
-# REQUIRES: x86
-
-## Confirm both mangled and unmangled names may appear in
-## the --dynamic-list file.
-
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
-
-# RUN: echo '{ _Z1fv; extern "C++" { "g()"; }; };' > %t.list
-# RUN: ld.lld -pie --dynamic-list %t.list %t.o -o %t
-# RUN: llvm-readelf --dyn-syms %t | FileCheck %s
-
-# CHECK:      Symbol table '.dynsym' contains 3 entries:
-# CHECK:      _Z1fv
-# CHECK-NEXT: _Z1gv
-
-.globl _Z1fv, _Z1gv
-_Z1fv:
-_Z1gv:

diff  --git a/lld/test/ELF/dynamic-list-glob.s b/lld/test/ELF/dynamic-list-glob.s
index 1a849782074ae..51c2949729338 100644
--- a/lld/test/ELF/dynamic-list-glob.s
+++ b/lld/test/ELF/dynamic-list-glob.s
@@ -1,22 +1,40 @@
 # REQUIRES: x86
-
-## Confirm --dynamic-list identifies symbols by entries, including wildcards.
-## Entries need not match a symbol. 
+## --dynamic-list entries may be wildcards. Entries need not match a symbol.
+## extern "C++" entries match demangled names, which for a non-mangled symbol
+## is the name itself.
 
 # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
 
 # RUN: echo '{ [fb]o?1*; };' > %t.list
 # RUN: ld.lld -pie --dynamic-list %t.list %t.o -o %t
 # RUN: llvm-readelf --dyn-syms %t | FileCheck %s
+# CHECK:      UND
+# CHECK-NEXT: [[#]] boo1
+# CHECK-NEXT: [[#]] foo1
+# CHECK-NEXT: [[#]] foo11
+# CHECK-NOT:  {{.}}
 
-# CHECK:      Symbol table '.dynsym' contains 4 entries:
-# CHECK:      boo1
-# CHECK-NEXT: foo1
-# CHECK-NEXT: foo11
+## Both mangled and unmangled names may appear.
+# RUN: echo '{ _Z1fv; extern "C++" { "g()"; h*; }; };' > %t.list
+# RUN: ld.lld -pie --dynamic-list %t.list %t.o -o %t
+# RUN: llvm-readelf --dyn-syms %t | FileCheck %s --check-prefix=CXX
+# CXX:      UND
+# CXX-NEXT: [[#]] _Z1fv
+# CXX-NEXT: [[#]] _Z1gv
+# CXX-NEXT: [[#]] _Z1hv
+# CXX-NEXT: [[#]] _Z2hhv
+# CXX-NEXT: [[#]] hello
+# CXX-NOT:  {{.}}
 
-.globl _start, boo1, foo1, foo11, foo2
+.globl _start, boo1, foo1, foo11, foo2, _Z1fv, _Z1gv, _Z1hv, _Z2hhv, _Z1iv, hello
 _start:
+boo1:
 foo1:
 foo11:
 foo2:
-boo1:
+_Z1fv:
+_Z1gv:
+_Z1hv:
+_Z2hhv:
+_Z1iv:
+hello:

diff  --git a/lld/test/ELF/version-script-reassign-glob.s b/lld/test/ELF/version-script-reassign-glob.s
deleted file mode 100644
index 8de36467bd8ee..0000000000000
--- a/lld/test/ELF/version-script-reassign-glob.s
+++ /dev/null
@@ -1,28 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
-
-# RUN: echo 'foo { foo*; }; bar { *; };' > %t.ver
-# RUN: ld.lld --version-script %t.ver %t.o -shared -o %t.so --fatal-warnings
-# RUN: llvm-readelf --dyn-syms %t.so | FileCheck --check-prefix=FOO %s
-
-# RUN: echo 'foo { foo*; }; bar { f*; };' > %t.ver
-# RUN: ld.lld --version-script %t.ver %t.o -shared -o %t.so --fatal-warnings
-# 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 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.
-## This is GNU linkers' behavior. We don't feel strongly this should be supported.
-# FOO: GLOBAL DEFAULT 7 foo@@foo
-
-# BAR: GLOBAL DEFAULT 7 foo@@bar
-
-## 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-wildcard-precedence.s b/lld/test/ELF/version-script-wildcard-precedence.s
new file mode 100644
index 0000000000000..bdd28363b6950
--- /dev/null
+++ b/lld/test/ELF/version-script-wildcard-precedence.s
@@ -0,0 +1,89 @@
+# REQUIRES: x86
+## Test precedence among version script wildcards.
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
+
+# RUN: ld.lld --version-script later.ver a.o -shared -o later.so --fatal-warnings
+# RUN: llvm-readelf --dyn-syms later.so | FileCheck %s -DV=bar
+# RUN: ld.lld --version-script node.ver a.o -shared -o node.so --fatal-warnings
+# RUN: llvm-readelf --dyn-syms node.so | FileCheck %s -DV=v1
+# RUN: ld.lld --version-script local.ver a.o -shared -o local.so --fatal-warnings
+# RUN: llvm-readelf --dyn-syms local.so | FileCheck %s -DV=v2
+
+# CHECK:      UND
+# CHECK-NEXT: [[#]] foo1@@[[V]]
+# CHECK-NEXT: [[#]] foo2@@[[V]]
+# CHECK-NEXT: [[#]] bar{{$}}
+# CHECK-NEXT: [[#]] _Z3fooi{{$}}
+# CHECK-NOT:  {{.}}
+
+## If both a non-* pattern and * match, non-* wins even if * comes later.
+## This is GNU linkers' behavior. We don't feel strongly this should be supported.
+# RUN: ld.lld --version-script star.ver a.o -shared -o star.so --fatal-warnings
+# RUN: llvm-readelf --dyn-syms star.so | FileCheck %s --check-prefix=STAR
+# STAR:      UND
+# STAR-NEXT: [[#]] foo1@@foo
+# STAR-NEXT: [[#]] foo2@@foo
+# STAR-NEXT: [[#]] bar@@bar
+# STAR-NEXT: [[#]] _Z3fooi@@bar
+# STAR-NOT:  {{.}}
+
+## When there are multiple * patterns, the last wins.
+# RUN: ld.lld --version-script star2.ver a.o -shared -o star2.so 2>&1 | \
+# RUN:   FileCheck %s --check-prefix=DUPWARN
+# RUN: llvm-readelf --dyn-syms star2.so | FileCheck %s --check-prefix=STAR2
+# DUPWARN: warning: wildcard pattern '*' is used for multiple version definitions in version script
+# STAR2:      UND
+# STAR2-NEXT: [[#]] foo1@@bar2
+# STAR2-NEXT: [[#]] foo2@@bar2
+# STAR2-NEXT: [[#]] bar@@bar2
+# STAR2-NEXT: [[#]] _Z3fooi@@bar2
+# STAR2-NOT:  {{.}}
+
+## An exact name beats a wildcard in a later definition.
+# RUN: ld.lld --version-script exact.ver a.o -shared -o exact.so --fatal-warnings
+# RUN: llvm-readelf --dyn-syms exact.so | FileCheck %s --check-prefix=EXACT
+# EXACT:      UND
+# EXACT-NEXT: [[#]] foo1@@v1
+# EXACT-NEXT: [[#]] foo2@@v2
+# EXACT-NOT:  {{.}}
+
+## An extern "C++" wildcard matches demangled names, which for a non-mangled
+## symbol is the name itself, and takes part in the same precedence.
+# RUN: ld.lld --version-script cxx.ver a.o -shared -o cxx.so --fatal-warnings
+# RUN: llvm-readelf --dyn-syms cxx.so | FileCheck %s --check-prefix=CXX
+# CXX:      UND
+# CXX-NEXT: [[#]] foo1@@v2
+# CXX-NEXT: [[#]] foo2@@v2
+# CXX-NEXT: [[#]] bar{{$}}
+# CXX-NEXT: [[#]] _Z3fooi@@v2
+# CXX-NOT:  {{.}}
+
+#--- a.s
+.globl foo1, foo2, bar, _Z3fooi
+foo1:
+foo2:
+bar:
+_Z3fooi:
+
+#--- later.ver
+foo { foo*; }; bar { f*; };
+
+#--- node.ver
+v1 { global: foo*; local: f*; };
+
+#--- local.ver
+v1 { local: f*; }; v2 { global: foo*; };
+
+#--- star.ver
+foo { foo*; }; bar { *; };
+
+#--- star2.ver
+bar1 { *; }; bar2 { *; };
+
+#--- exact.ver
+v1 { global: foo1; local: *; }; v2 { global: foo*; };
+
+#--- cxx.ver
+v1 { global: foo*; }; v2 { global: extern "C++" { foo*; }; };


        


More information about the llvm-commits mailing list