From 6b97268c56ae8baa684da5de23ae2ebc41d94a1d Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Wed, 4 Aug 2021 22:29:30 -0700 Subject: [PATCH] Revert "[ELF] Apply version script patterns to non-default version symbols" This reverts commit 7ed22a6fa90cbdc70d6806c1121a0c50c1978dce. buf is not cleared so the commit misses some cases. (cherry picked from commit a533eb7423acad49f10426cd78dc8e7e66a6365f) --- lld/ELF/Config.h | 3 +- lld/ELF/Driver.cpp | 9 +- lld/ELF/ScriptParser.cpp | 9 +- lld/ELF/SymbolTable.cpp | 91 +++++-------- lld/ELF/SymbolTable.h | 8 +- lld/ELF/Symbols.cpp | 3 - lld/test/ELF/version-script-extern-exact.s | 30 +++++ .../ELF/version-script-extern-wildcards.s | 28 ++++ lld/test/ELF/version-script-extern.s | 120 ++++++++++++++++++ lld/test/ELF/version-script-noundef.s | 4 - lld/test/ELF/version-script-symver-extern.s | 38 ------ lld/test/ELF/version-script-symver.s | 2 + 12 files changed, 224 insertions(+), 121 deletions(-) create mode 100644 lld/test/ELF/version-script-extern-exact.s create mode 100644 lld/test/ELF/version-script-extern-wildcards.s create mode 100644 lld/test/ELF/version-script-extern.s delete mode 100644 lld/test/ELF/version-script-symver-extern.s diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index e1abb4dfab36..a996a815599a 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -86,8 +86,7 @@ struct SymbolVersion { struct VersionDefinition { llvm::StringRef name; uint16_t id; - std::vector nonLocalPatterns; - std::vector localPatterns; + std::vector patterns; }; // This struct contains the global configuration for the linker. diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 594c20016827..713d1f7cc360 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1351,19 +1351,18 @@ static void readConfigs(opt::InputArgList &args) { } assert(config->versionDefinitions.empty()); + config->versionDefinitions.push_back({"local", (uint16_t)VER_NDX_LOCAL, {}}); config->versionDefinitions.push_back( - {"local", (uint16_t)VER_NDX_LOCAL, {}, {}}); - config->versionDefinitions.push_back( - {"global", (uint16_t)VER_NDX_GLOBAL, {}, {}}); + {"global", (uint16_t)VER_NDX_GLOBAL, {}}); // If --retain-symbol-file is used, we'll keep only the symbols listed in // the file and discard all others. if (auto *arg = args.getLastArg(OPT_retain_symbols_file)) { - config->versionDefinitions[VER_NDX_LOCAL].nonLocalPatterns.push_back( + config->versionDefinitions[VER_NDX_LOCAL].patterns.push_back( {"*", /*isExternCpp=*/false, /*hasWildcard=*/true}); if (Optional buffer = readFile(arg->getValue())) for (StringRef s : args::getLines(*buffer)) - config->versionDefinitions[VER_NDX_GLOBAL].nonLocalPatterns.push_back( + config->versionDefinitions[VER_NDX_GLOBAL].patterns.push_back( {s, /*isExternCpp=*/false, /*hasWildcard=*/false}); } diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index 1c743fd47747..2c980eb810c7 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -1496,9 +1496,9 @@ void ScriptParser::readAnonymousDeclaration() { std::vector globals; std::tie(locals, globals) = readSymbols(); for (const SymbolVersion &pat : locals) - config->versionDefinitions[VER_NDX_LOCAL].localPatterns.push_back(pat); + config->versionDefinitions[VER_NDX_LOCAL].patterns.push_back(pat); for (const SymbolVersion &pat : globals) - config->versionDefinitions[VER_NDX_GLOBAL].nonLocalPatterns.push_back(pat); + config->versionDefinitions[VER_NDX_GLOBAL].patterns.push_back(pat); expect(";"); } @@ -1510,12 +1510,13 @@ void ScriptParser::readVersionDeclaration(StringRef verStr) { std::vector locals; std::vector globals; std::tie(locals, globals) = readSymbols(); + for (const SymbolVersion &pat : locals) + config->versionDefinitions[VER_NDX_LOCAL].patterns.push_back(pat); // Create a new version definition and add that to the global symbols. VersionDefinition ver; ver.name = verStr; - ver.nonLocalPatterns = std::move(globals); - ver.localPatterns = std::move(locals); + ver.patterns = globals; ver.id = config->versionDefinitions.size(); config->versionDefinitions.push_back(ver); diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index 96a9cf1d1617..70aea288c53f 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -150,24 +150,19 @@ std::vector SymbolTable::findByVersion(SymbolVersion ver) { return {}; } -std::vector SymbolTable::findAllByVersion(SymbolVersion ver, - bool includeNonDefault) { +std::vector SymbolTable::findAllByVersion(SymbolVersion ver) { std::vector res; SingleStringMatcher m(ver.name); if (ver.isExternCpp) { for (auto &p : getDemangledSyms()) if (m.match(p.first())) - for (Symbol *sym : p.second) - if (includeNonDefault || !sym->getName().contains('@')) - res.push_back(sym); + res.insert(res.end(), p.second.begin(), p.second.end()); return res; } for (Symbol *sym : symVector) - if (canBeVersioned(*sym) && - (includeNonDefault || !sym->getName().contains('@')) && - m.match(sym->getName())) + if (canBeVersioned(*sym) && m.match(sym->getName())) res.push_back(sym); return res; } @@ -177,7 +172,7 @@ void SymbolTable::handleDynamicList() { for (SymbolVersion &ver : config->dynamicList) { std::vector syms; if (ver.hasWildcard) - syms = findAllByVersion(ver, /*includeNonDefault=*/true); + syms = findAllByVersion(ver); else syms = findByVersion(ver); @@ -186,12 +181,21 @@ void SymbolTable::handleDynamicList() { } } -// Set symbol versions to symbols. This function handles patterns containing no -// wildcard characters. Return false if no symbol definition matches ver. -bool SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId, +// Set symbol versions to symbols. This function handles patterns +// containing no wildcard characters. +void SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId, StringRef versionName) { + if (ver.hasWildcard) + return; + // Get a list of symbols which we need to assign the version to. std::vector syms = findByVersion(ver); + if (syms.empty()) { + if (!config->undefinedVersion) + error("version script assignment of '" + versionName + "' to symbol '" + + ver.name + "' failed: symbol not defined"); + return; + } auto getName = [](uint16_t ver) -> std::string { if (ver == VER_NDX_LOCAL) @@ -203,10 +207,10 @@ bool SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId, // Assign the version. for (Symbol *sym : syms) { - // For a non-local versionId, skip symbols containing version info because - // symbol versions specified by symbol names take precedence over version - // scripts. See parseSymbolVersion(). - if (versionId != VER_NDX_LOCAL && sym->getName().contains('@')) + // Skip symbols containing version info because symbol versions + // specified by symbol names take precedence over version scripts. + // See parseSymbolVersion(). + if (sym->getName().contains('@')) continue; // If the version has not been assigned, verdefIndex is -1. Use an arbitrary @@ -221,15 +225,13 @@ bool SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId, warn("attempt to reassign symbol '" + ver.name + "' of " + getName(sym->versionId) + " to " + getName(versionId)); } - return !syms.empty(); } -void SymbolTable::assignWildcardVersion(SymbolVersion ver, uint16_t versionId, - bool includeNonDefault) { +void SymbolTable::assignWildcardVersion(SymbolVersion ver, uint16_t versionId) { // Exact matching takes precedence over fuzzy matching, // so we set a version to a symbol only if no version has been assigned // to the symbol. This behavior is compatible with GNU. - for (Symbol *sym : findAllByVersion(ver, includeNonDefault)) + for (Symbol *sym : findAllByVersion(ver)) if (sym->verdefIndex == UINT32_C(-1)) { sym->verdefIndex = 0; sym->versionId = versionId; @@ -242,57 +244,26 @@ void SymbolTable::assignWildcardVersion(SymbolVersion ver, uint16_t versionId, // script file, the script does not actually define any symbol version, // but just specifies symbols visibilities. void SymbolTable::scanVersionScript() { - SmallString<128> buf; // First, we assign versions to exact matching symbols, // i.e. version definitions not containing any glob meta-characters. - std::vector syms; - for (VersionDefinition &v : config->versionDefinitions) { - auto assignExact = [&](SymbolVersion pat, uint16_t id, StringRef ver) { - bool found = assignExactVersion(pat, id, ver); - found |= assignExactVersion({(pat.name + "@" + v.name).toStringRef(buf), - pat.isExternCpp, /*hasWildCard=*/false}, - id, ver); - if (!found && !config->undefinedVersion) - errorOrWarn("version script assignment of '" + ver + "' to symbol '" + - pat.name + "' failed: symbol not defined"); - }; - for (SymbolVersion &pat : v.nonLocalPatterns) - if (!pat.hasWildcard) - assignExact(pat, v.id, v.name); - for (SymbolVersion pat : v.localPatterns) - if (!pat.hasWildcard) - assignExact(pat, VER_NDX_LOCAL, "local"); - } + for (VersionDefinition &v : config->versionDefinitions) + for (SymbolVersion &pat : v.patterns) + assignExactVersion(pat, v.id, v.name); // Next, assign versions to wildcards that are not "*". Note that because the // last match takes precedence over previous matches, we iterate over the // definitions in the reverse order. - auto assignWildcard = [&](SymbolVersion pat, uint16_t id, StringRef ver) { - assignWildcardVersion(pat, id, /*includeNonDefault=*/false); - assignWildcardVersion({(pat.name + "@" + ver).toStringRef(buf), - pat.isExternCpp, /*hasWildCard=*/true}, - id, - /*includeNonDefault=*/true); - }; - for (VersionDefinition &v : llvm::reverse(config->versionDefinitions)) { - for (SymbolVersion &pat : v.nonLocalPatterns) + for (VersionDefinition &v : llvm::reverse(config->versionDefinitions)) + for (SymbolVersion &pat : v.patterns) if (pat.hasWildcard && pat.name != "*") - assignWildcard(pat, v.id, v.name); - for (SymbolVersion &pat : v.localPatterns) - if (pat.hasWildcard && pat.name != "*") - assignWildcard(pat, VER_NDX_LOCAL, v.name); - } + assignWildcardVersion(pat, v.id); // Then, assign versions to "*". In GNU linkers they have lower priority than // other wildcards. - for (VersionDefinition &v : config->versionDefinitions) { - for (SymbolVersion &pat : v.nonLocalPatterns) + for (VersionDefinition &v : config->versionDefinitions) + for (SymbolVersion &pat : v.patterns) if (pat.hasWildcard && pat.name == "*") - assignWildcard(pat, v.id, v.name); - for (SymbolVersion &pat : v.localPatterns) - if (pat.hasWildcard && pat.name == "*") - assignWildcard(pat, VER_NDX_LOCAL, v.name); - } + assignWildcardVersion(pat, v.id); // Symbol themselves might know their versions because symbols // can contain versions in the form of @. diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h index 22a1c59ce933..507af8d2be75 100644 --- a/lld/ELF/SymbolTable.h +++ b/lld/ELF/SymbolTable.h @@ -65,14 +65,12 @@ public: private: std::vector findByVersion(SymbolVersion ver); - std::vector findAllByVersion(SymbolVersion ver, - bool includeNonDefault); + std::vector findAllByVersion(SymbolVersion ver); llvm::StringMap> &getDemangledSyms(); - bool assignExactVersion(SymbolVersion ver, uint16_t versionId, + void assignExactVersion(SymbolVersion ver, uint16_t versionId, StringRef versionName); - void assignWildcardVersion(SymbolVersion ver, uint16_t versionId, - bool includeNonDefault); + void assignWildcardVersion(SymbolVersion ver, uint16_t versionId); // The order the global symbols are in is not defined. We can use an arbitrary // order, but it has to be reproducible. That is true even when cross linking. diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index cef303f05f89..496be33dd182 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -208,9 +208,6 @@ OutputSection *Symbol::getOutputSection() const { // If a symbol name contains '@', the characters after that is // a symbol version name. This function parses that. void Symbol::parseSymbolVersion() { - // Return if localized by a local: pattern in a version script. - if (versionId == VER_NDX_LOCAL) - return; StringRef s = getName(); size_t pos = s.find('@'); if (pos == 0 || pos == StringRef::npos) diff --git a/lld/test/ELF/version-script-extern-exact.s b/lld/test/ELF/version-script-extern-exact.s new file mode 100644 index 000000000000..f00b3acc7738 --- /dev/null +++ b/lld/test/ELF/version-script-extern-exact.s @@ -0,0 +1,30 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "FOO { global: extern \"C++\" { \"aaa*\"; }; };" > %t.script +# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so +# RUN: llvm-readobj --dyn-syms %t.so | FileCheck %s --check-prefix=NOMATCH + +# NOMATCH: DynamicSymbols [ +# NOMATCH-NOT: _Z3aaaPi@@FOO +# NOMATCH-NOT: _Z3aaaPf@@FOO +# NOMATCH: ] + +# RUN: echo "FOO { global: extern \"C++\" { \"aaa*\"; aaa*; }; };" > %t2.script +# RUN: ld.lld --version-script %t2.script -shared %t.o -o %t2.so +# RUN: llvm-readobj --dyn-syms %t2.so | FileCheck %s --check-prefix=MATCH +# MATCH: DynamicSymbols [ +# MATCH: _Z3aaaPi@@FOO +# MATCH: _Z3aaaPf@@FOO +# MATCH: ] + +.text +.globl _Z3aaaPi +.type _Z3aaaPi,@function +_Z3aaaPi: +retq + +.globl _Z3aaaPf +.type _Z3aaaPf,@function +_Z3aaaPf: +retq diff --git a/lld/test/ELF/version-script-extern-wildcards.s b/lld/test/ELF/version-script-extern-wildcards.s new file mode 100644 index 000000000000..18ce20bc605d --- /dev/null +++ b/lld/test/ELF/version-script-extern-wildcards.s @@ -0,0 +1,28 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "FOO { global: extern \"C++\" { foo*; }; };" > %t.script +# RUN: echo "BAR { global: extern \"C++\" { zed*; bar; }; };" >> %t.script +# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so +# RUN: llvm-readobj -V --dyn-syms %t.so | FileCheck %s + +# CHECK: VersionSymbols [ +# CHECK: Name: _Z3fooi@@FOO +# CHECK: Name: _Z3bari +# CHECK: Name: _Z3zedi@@BAR + +.text +.globl _Z3fooi +.type _Z3fooi,@function +_Z3fooi: +retq + +.globl _Z3bari +.type _Z3bari,@function +_Z3bari: +retq + +.globl _Z3zedi +.type _Z3zedi,@function +_Z3zedi: +retq diff --git a/lld/test/ELF/version-script-extern.s b/lld/test/ELF/version-script-extern.s new file mode 100644 index 000000000000..29059eac8e40 --- /dev/null +++ b/lld/test/ELF/version-script-extern.s @@ -0,0 +1,120 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "LIBSAMPLE_1.0 { global:" > %t.script +# RUN: echo ' extern "C++" { "foo(int)"; "zed(int)"; "abc::abc()"; };' >> %t.script +# RUN: echo "};" >> %t.script +# RUN: echo "LIBSAMPLE_2.0 { global:" >> %t.script +# RUN: echo ' extern "C" { _Z3bari; };' >> %t.script +# RUN: echo "};" >> %t.script +# RUN: ld.lld --hash-style=sysv --version-script %t.script -soname fixed-length-string -shared %t.o -o %t.so +# RUN: llvm-readobj -V --dyn-syms %t.so | FileCheck --check-prefix=DSO %s + +# DSO: DynamicSymbols [ +# DSO-NEXT: Symbol { +# DSO-NEXT: Name: +# DSO-NEXT: Value: 0x0 +# DSO-NEXT: Size: 0 +# DSO-NEXT: Binding: Local +# DSO-NEXT: Type: None +# DSO-NEXT: Other: 0 +# DSO-NEXT: Section: Undefined +# DSO-NEXT: } +# DSO-NEXT: Symbol { +# DSO-NEXT: Name: _Z3fooi@@LIBSAMPLE_1.0 +# DSO-NEXT: Value: +# DSO-NEXT: Size: 0 +# DSO-NEXT: Binding: Global +# DSO-NEXT: Type: Function +# DSO-NEXT: Other: 0 +# DSO-NEXT: Section: .text +# DSO-NEXT: } +# DSO-NEXT: Symbol { +# DSO-NEXT: Name: _Z3bari@@LIBSAMPLE_2.0 +# DSO-NEXT: Value: +# DSO-NEXT: Size: 0 +# DSO-NEXT: Binding: Global +# DSO-NEXT: Type: Function +# DSO-NEXT: Other: 0 +# DSO-NEXT: Section: .text +# DSO-NEXT: } +# DSO-NEXT: Symbol { +# DSO-NEXT: Name: _Z3zedi@@LIBSAMPLE_1.0 +# DSO-NEXT: Value: +# DSO-NEXT: Size: 0 +# DSO-NEXT: Binding: Global (0x1) +# DSO-NEXT: Type: Function (0x2) +# DSO-NEXT: Other: 0 +# DSO-NEXT: Section: .text (0x6) +# DSO-NEXT: } +# DSO-NEXT: Symbol { +# DSO-NEXT: Name: _ZN3abcC1Ev@@LIBSAMPLE_1.0 +# DSO-NEXT: Value: +# DSO-NEXT: Size: 0 +# DSO-NEXT: Binding: Global (0x1) +# DSO-NEXT: Type: Function (0x2) +# DSO-NEXT: Other: 0 +# DSO-NEXT: Section: .text (0x6) +# DSO-NEXT: } +# DSO-NEXT: Symbol { +# DSO-NEXT: Name: _ZN3abcC2Ev@@LIBSAMPLE_1.0 +# DSO-NEXT: Value: +# DSO-NEXT: Size: 0 +# DSO-NEXT: Binding: Global (0x1) +# DSO-NEXT: Type: Function (0x2) +# DSO-NEXT: Other: 0 +# DSO-NEXT: Section: .text (0x6) +# DSO-NEXT: } +# DSO-NEXT: ] +# DSO-NEXT: VersionSymbols [ +# DSO-NEXT: Symbol { +# DSO-NEXT: Version: 0 +# DSO-NEXT: Name: +# DSO-NEXT: } +# DSO-NEXT: Symbol { +# DSO-NEXT: Version: 2 +# DSO-NEXT: Name: _Z3fooi@@LIBSAMPLE_1.0 +# DSO-NEXT: } +# DSO-NEXT: Symbol { +# DSO-NEXT: Version: 3 +# DSO-NEXT: Name: _Z3bari@@LIBSAMPLE_2.0 +# DSO-NEXT: } +# DSO-NEXT: Symbol { +# DSO-NEXT: Version: 2 +# DSO-NEXT: Name: _Z3zedi@@LIBSAMPLE_1.0 +# DSO-NEXT: } +# DSO-NEXT: Symbol { +# DSO-NEXT: Version: 2 +# DSO-NEXT: Name: _ZN3abcC1Ev@@LIBSAMPLE_1.0 +# DSO-NEXT: } +# DSO-NEXT: Symbol { +# DSO-NEXT: Version: 2 +# DSO-NEXT: Name: _ZN3abcC2Ev@@LIBSAMPLE_1.0 +# DSO-NEXT: } +# DSO-NEXT: ] + +.text +.globl _Z3fooi +.type _Z3fooi,@function +_Z3fooi: +retq + +.globl _Z3bari +.type _Z3bari,@function +_Z3bari: +retq + +.globl _Z3zedi +.type _Z3zedi,@function +_Z3zedi: +retq + +.globl _ZN3abcC1Ev +.type _ZN3abcC1Ev,@function +_ZN3abcC1Ev: +retq + +.globl _ZN3abcC2Ev +.type _ZN3abcC2Ev,@function +_ZN3abcC2Ev: +retq diff --git a/lld/test/ELF/version-script-noundef.s b/lld/test/ELF/version-script-noundef.s index 18916b66f064..0c48622fd4c1 100644 --- a/lld/test/ELF/version-script-noundef.s +++ b/lld/test/ELF/version-script-noundef.s @@ -18,10 +18,6 @@ # RUN: %t.o -o %t.so 2>&1 | FileCheck -check-prefix=ERR3 %s # ERR3: version script assignment of 'local' to symbol 'und' failed: symbol not defined -## Wildcard patterns do not error. -# RUN: echo "VERSION_1.0 { global: b*; local: u*; };" > %t4.script -# RUN: ld.lld --version-script %t4.script -shared --no-undefined-version --fatal-warnings %t.o -o /dev/null - .text .globl foo .type foo,@function diff --git a/lld/test/ELF/version-script-symver-extern.s b/lld/test/ELF/version-script-symver-extern.s deleted file mode 100644 index 93afb7f270ad..000000000000 --- a/lld/test/ELF/version-script-symver-extern.s +++ /dev/null @@ -1,38 +0,0 @@ -# REQUIRES: x86 - -# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o - -# RUN: echo 'v1 { local: extern "C++" { "foo1()"; }; }; v2 { local: extern "C++" { "foo2()"; }; };' > %t1.script -# RUN: ld.lld --version-script %t1.script -shared %t.o -o %t1.so -# RUN: llvm-readelf --dyn-syms %t1.so | FileCheck --check-prefix=EXACT %s -# EXACT: UND -# EXACT-NEXT: [[#]] _start{{$}} -# EXACT-NEXT: [[#]] _Z4foo3i@v1 -# EXACT-NEXT: [[#]] _Z4foo4i@@v2 -# EXACT-NOT: {{.}} - -# RUN: echo 'v1 { global: *; local: extern "C++" {foo*;}; }; v2 {};' > %t2.script -# RUN: ld.lld --version-script %t2.script -shared %t.o -o %t2.so -# RUN: llvm-readelf --dyn-syms %t2.so | FileCheck --check-prefix=MIX1 %s -# MIX1: UND -# MIX1-NEXT: [[#]] _start@@v1 -# MIX1-NEXT: [[#]] _Z4foo3i@v1 -# MIX1-NEXT: [[#]] _Z4foo4i@@v2 -# MIX1-NOT: {{.}} - -# RUN: echo 'v1 { global: extern "C++" {foo*;}; local: *; }; v2 { global: extern "C++" {"foo4(int)";}; local: *; };' > %t3.script -# RUN: ld.lld --version-script %t3.script -shared %t.o -o %t3.so -# RUN: llvm-readelf --dyn-syms %t3.so | FileCheck --check-prefix=MIX2 %s -# MIX2: UND -# MIX2-NEXT: [[#]] _Z4foo1v@@v1 -# MIX2-NEXT: [[#]] _Z4foo2v@@v1 -# MIX2-NEXT: [[#]] _Z4foo3i@v1 -# MIX2-NEXT: [[#]] _Z4foo4i@@v2 -# MIX2-NOT: {{.}} - -.globl _Z4foo1v; _Z4foo1v: ret -.globl _Z4foo2v; _Z4foo2v: ret -.globl _Z4foo3i; .symver _Z4foo3i,_Z4foo3i@v1,remove; _Z4foo3i: ret -.globl _Z4foo4i; .symver _Z4foo4i,_Z4foo4i@@@v2; _Z4foo4i: ret - -.globl _start; _start: ret diff --git a/lld/test/ELF/version-script-symver.s b/lld/test/ELF/version-script-symver.s index a3a820f9edea..cbf6e140bb30 100644 --- a/lld/test/ELF/version-script-symver.s +++ b/lld/test/ELF/version-script-symver.s @@ -19,6 +19,7 @@ # WC: UND # WC-NEXT: [[#]] foo4@@v2 # WC-NEXT: [[#]] _start{{$}} +# WC-NEXT: [[#]] foo3@v1 # WC-NOT: {{.}} # RUN: echo 'v1 { global: *; local: foo*; }; v2 {};' > %t3.script @@ -27,6 +28,7 @@ # MIX1: UND # MIX1-NEXT: [[#]] foo4@@v2 # MIX1-NEXT: [[#]] _start@@v1 +# MIX1-NEXT: [[#]] foo3@v1 # MIX1-NOT: {{.}} # RUN: echo 'v1 { global: foo*; local: *; }; v2 { global: foo4; local: *; };' > %t4.script