[ELF] - Versionscript: do not treat non-wildcarded names as wildcards.
Previously we incorrectly handled cases when symbol name in extern c++ tag was enclosed in quotes. Next case was treated as wildcard: GLIBCXX_3.4 { extern "C++" { "aaa*" } But it should have not. Quotes around aaa here means that we should have do exact name matching. That is PR30268 which has name with pointer is interpreted as wildcard by lld: extern "C++" { "operator delete[](void*)"; Patch fixes the issue. Differential revision: https://reviews.llvm.org/D24229 llvm-svn: 281038
This commit is contained in:
parent
25d1286e5a
commit
d220384376
|
@ -45,6 +45,7 @@ enum class UnresolvedPolicy { NoUndef, ReportError, Warn, Ignore };
|
|||
struct SymbolVersion {
|
||||
llvm::StringRef Name;
|
||||
bool IsExternCpp;
|
||||
bool HasWildcards;
|
||||
};
|
||||
|
||||
// This struct contains symbols version definition that
|
||||
|
|
|
@ -780,12 +780,18 @@ void ScriptParser::addFile(StringRef S) {
|
|||
}
|
||||
}
|
||||
|
||||
static StringRef unquote(StringRef S) {
|
||||
if (!S.startswith("\""))
|
||||
return S;
|
||||
return S.substr(1, S.size() - 2);
|
||||
}
|
||||
|
||||
void ScriptParser::readAsNeeded() {
|
||||
expect("(");
|
||||
bool Orig = Config->AsNeeded;
|
||||
Config->AsNeeded = true;
|
||||
while (!Error && !skip(")"))
|
||||
addFile(next());
|
||||
addFile(unquote(next()));
|
||||
Config->AsNeeded = Orig;
|
||||
}
|
||||
|
||||
|
@ -811,7 +817,7 @@ void ScriptParser::readGroup() {
|
|||
if (Tok == "AS_NEEDED")
|
||||
readAsNeeded();
|
||||
else
|
||||
addFile(Tok);
|
||||
addFile(unquote(Tok));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1004,7 +1010,7 @@ Expr ScriptParser::readAssert() {
|
|||
expect("(");
|
||||
Expr E = readExpr();
|
||||
expect(",");
|
||||
StringRef Msg = next();
|
||||
StringRef Msg = unquote(next());
|
||||
expect(")");
|
||||
return [=](uint64_t Dot) {
|
||||
uint64_t V = E(Dot);
|
||||
|
@ -1421,13 +1427,14 @@ void ScriptParser::readLocal() {
|
|||
}
|
||||
|
||||
void ScriptParser::readExtern(std::vector<SymbolVersion> *Globals) {
|
||||
expect("C++");
|
||||
expect("\"C++\"");
|
||||
expect("{");
|
||||
|
||||
for (;;) {
|
||||
if (peek() == "}" || Error)
|
||||
break;
|
||||
Globals->push_back({next(), true});
|
||||
bool HasWildcard = !peek().startswith("\"") && hasWildcard(peek());
|
||||
Globals->push_back({unquote(next()), true, HasWildcard});
|
||||
expect(";");
|
||||
}
|
||||
|
||||
|
@ -1450,7 +1457,7 @@ void ScriptParser::readGlobal(StringRef VerStr) {
|
|||
if (Cur == "}" || Cur == "local:" || Error)
|
||||
return;
|
||||
next();
|
||||
Globals->push_back({Cur, false});
|
||||
Globals->push_back({unquote(Cur), false, hasWildcard(Cur)});
|
||||
expect(";");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,14 +60,17 @@ std::vector<StringRef> ScriptParserBase::tokenize(StringRef S) {
|
|||
if (S.empty())
|
||||
return Ret;
|
||||
|
||||
// Quoted token.
|
||||
// Quoted token. Note that double-quote characters are parts of a token
|
||||
// because, in a glob match context, only unquoted tokens are interpreted
|
||||
// as glob patterns. Double-quoted tokens are literal patterns in that
|
||||
// context.
|
||||
if (S.startswith("\"")) {
|
||||
size_t E = S.find("\"", 1);
|
||||
if (E == StringRef::npos) {
|
||||
error("unclosed quote");
|
||||
return {};
|
||||
}
|
||||
Ret.push_back(S.substr(1, E - 1));
|
||||
Ret.push_back(S.take_front(E + 1));
|
||||
S = S.substr(E + 1);
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "Config.h"
|
||||
#include "Error.h"
|
||||
#include "LinkerScript.h"
|
||||
#include "Strings.h"
|
||||
#include "SymbolListFile.h"
|
||||
#include "Symbols.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
|
@ -678,7 +677,7 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
|
|||
// i.e. version definitions not containing any glob meta-characters.
|
||||
for (VersionDefinition &V : Config->VersionDefinitions) {
|
||||
for (SymbolVersion Sym : V.Globals) {
|
||||
if (hasWildcard(Sym.Name))
|
||||
if (Sym.HasWildcards)
|
||||
continue;
|
||||
StringRef N = Sym.Name;
|
||||
SymbolBody *B = Sym.IsExternCpp ? findDemangled(Demangled, N) : find(N);
|
||||
|
@ -693,7 +692,7 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
|
|||
for (size_t I = Config->VersionDefinitions.size() - 1; I != (size_t)-1; --I) {
|
||||
VersionDefinition &V = Config->VersionDefinitions[I];
|
||||
for (SymbolVersion &Sym : V.Globals) {
|
||||
if (!hasWildcard(Sym.Name))
|
||||
if (!Sym.HasWildcards)
|
||||
continue;
|
||||
Regex Re = compileGlobPatterns({Sym.Name});
|
||||
std::vector<SymbolBody *> Syms =
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# 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 -V -dyn-symbols %t.so | FileCheck %s
|
||||
|
||||
# CHECK: Symbol {
|
||||
# CHECK: Name: _Z3aaaPf@ (1)
|
||||
# CHECK: Symbol {
|
||||
# CHECK: Name: _Z3aaaPi@ (10)
|
||||
|
||||
.text
|
||||
.globl _Z3aaaPi
|
||||
.type _Z3aaaPi,@function
|
||||
_Z3aaaPi:
|
||||
retq
|
||||
|
||||
.globl _Z3aaaPf
|
||||
.type _Z3aaaPf,@function
|
||||
_Z3aaaPf:
|
||||
retq
|
Loading…
Reference in New Issue