| From be8275753fe23fb56c4cb5127695dad540b9053c Mon Sep 17 00:00:00 2001 |
| From: Fangrui Song <maskray@google.com> |
| Date: Thu, 11 Jul 2019 11:16:44 +0000 |
| Subject: [PATCH] [ELF] Warn rather than error when duplicate version |
| assignments occur |
| |
| In lvm2, libdevmapper.so is linked with a version script with duplicate |
| version assignments: |
| |
| DM_1_02_138 { global: ... dm_bitset_parse_list; ... }; |
| DM_1_02_129 { global: ... dm_bitset_parse_list; ... }; |
| |
| ld.bfd silently accepts this while gold issues a warning. We currently |
| error, thus inhibit producing the executable. Change the error to |
| warning to allow this case, and improve the message. |
| |
| There are some cases where ld.bfd error |
| `anonymous version tag cannot be combined with other version tags` |
| but we just warn. It is probably OK for now. |
| |
| Reviewed By: grimar, ruiu |
| |
| Differential Revision: https://reviews.llvm.org/D64549 |
| |
| llvm-svn: 365759 |
| --- |
| lld/ELF/SymbolTable.cpp | 19 ++++++++++++---- |
| lld/test/ELF/version-script-reassign.s | 31 ++++++++++++++++++++++++++ |
| lld/test/ELF/version-script.s | 6 ----- |
| 3 files changed, 46 insertions(+), 10 deletions(-) |
| create mode 100644 lld/test/ELF/version-script-reassign.s |
| |
| diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp |
| index 0fd0eab9bda..252e1201c0c 100644 |
| --- a/lld/ELF/SymbolTable.cpp |
| +++ b/lld/ELF/SymbolTable.cpp |
| @@ -201,6 +201,14 @@ void SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId, |
| return; |
| } |
| |
| + auto getName = [](uint16_t ver) -> std::string { |
| + if (ver == VER_NDX_LOCAL) |
| + return "VER_NDX_LOCAL"; |
| + if (ver == VER_NDX_GLOBAL) |
| + return "VER_NDX_GLOBAL"; |
| + return ("version '" + config->versionDefinitions[ver - 2].name + "'").str(); |
| + }; |
| + |
| // Assign the version. |
| for (Symbol *sym : syms) { |
| // Skip symbols containing version info because symbol versions |
| @@ -209,10 +217,13 @@ void SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId, |
| if (sym->getName().contains('@')) |
| continue; |
| |
| - if (sym->versionId != config->defaultSymbolVersion && |
| - sym->versionId != versionId) |
| - error("duplicate symbol '" + ver.name + "' in version script"); |
| - sym->versionId = versionId; |
| + if (sym->versionId == config->defaultSymbolVersion) |
| + sym->versionId = versionId; |
| + if (sym->versionId == versionId) |
| + continue; |
| + |
| + warn("attempt to reassign symbol '" + ver.name + "' of " + |
| + getName(sym->versionId) + " to " + getName(versionId)); |
| } |
| } |
| |
| diff --git a/lld/test/ELF/version-script-reassign.s b/lld/test/ELF/version-script-reassign.s |
| new file mode 100644 |
| index 00000000000..e2413295cc4 |
| --- /dev/null |
| +++ b/lld/test/ELF/version-script-reassign.s |
| @@ -0,0 +1,31 @@ |
| +# REQUIRES: x86 |
| +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o |
| +# RUN: echo '{ local: foo; };' > %tl.ver |
| +# RUN: echo '{ global: foo; local: *; };' > %tg.ver |
| +# RUN: echo 'V1 { global: foo; };' > %t1.ver |
| +# RUN: echo 'V2 { global: foo; };' > %t2.ver |
| + |
| +## Note, ld.bfd errors on the two cases. |
| +# RUN: ld.lld -shared %t.o --version-script %tl.ver --version-script %t1.ver \ |
| +# RUN: -o %t.so 2>&1 | FileCheck --check-prefix=LOCAL %s |
| +# RUN: llvm-readelf --dyn-syms %t.so | FileCheck --check-prefix=LOCAL-SYM %s |
| +# RUN: ld.lld -shared %t.o --version-script %tg.ver --version-script %t1.ver \ |
| +# RUN: -o %t.so 2>&1 | FileCheck --check-prefix=GLOBAL %s |
| +# RUN: llvm-readelf --dyn-syms %t.so | FileCheck --check-prefix=GLOBAL-SYM %s |
| + |
| +## Note, ld.bfd silently accepts this case. |
| +# RUN: ld.lld -shared %t.o --version-script %t1.ver --version-script %t2.ver \ |
| +# RUN: -o %t.so 2>&1 | FileCheck --check-prefix=V1-WARN %s |
| +# RUN: llvm-readelf --dyn-syms %t.so | FileCheck --check-prefix=V1-SYM %s |
| + |
| +# LOCAL: warning: attempt to reassign symbol 'foo' of VER_NDX_LOCAL to version 'V1' |
| +# LOCAL-SYM-NOT: foo |
| + |
| +# GLOBAL: warning: attempt to reassign symbol 'foo' of VER_NDX_GLOBAL to version 'V1' |
| +# GLOBAL-SYM: foo{{$}} |
| + |
| +# V1-WARN: warning: attempt to reassign symbol 'foo' of version 'V1' to version 'V2' |
| +# V1-SYM: foo@@V1 |
| + |
| +.globl foo |
| +foo: |
| diff --git a/lld/test/ELF/version-script.s b/lld/test/ELF/version-script.s |
| index bba503b2d2e..8bbd769d33f 100644 |
| --- a/lld/test/ELF/version-script.s |
| +++ b/lld/test/ELF/version-script.s |
| @@ -32,12 +32,6 @@ |
| # RUN: FileCheck -check-prefix=ERR2 %s |
| # ERR2: EOF expected, but got VERSION_2.0 |
| |
| -# RUN: echo "VERSION_1.0 { global: foo1; local: *; };" > %t6.script |
| -# RUN: echo "VERSION_2.0 { global: foo1; local: *; };" >> %t6.script |
| -# RUN: not ld.lld --version-script %t6.script -shared %t.o %t2.so -o /dev/null 2>&1 | \ |
| -# RUN: FileCheck -check-prefix=ERR3 %s |
| -# ERR3: duplicate symbol 'foo1' in version script |
| - |
| # RUN: echo "{ foo1; foo2; };" > %t.list |
| # RUN: ld.lld --version-script %t.script --dynamic-list %t.list %t.o %t2.so -o %t2 |
| # RUN: llvm-readobj %t2 > /dev/null |
| -- |
| 2.22.0.657.g960e92d24f-goog |
| |