[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
This commit is contained in:
Fangrui Song 2019-07-11 11:16:44 +00:00
parent e23be09e66
commit be8275753f
3 changed files with 46 additions and 10 deletions

View File

@ -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));
}
}

View File

@ -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:

View File

@ -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