Linker script: support VERSION command.

Summary:
VERSION commands define symbol versions. The grammar of the
commnad is as follows

  VERSION { version-script-commands }

where version-script-commands is

  [ name ] { version-definitions }.

Note that we already support version-script-commands because
it is being used for version script command.

This patch is based on George's patch https://reviews.llvm.org/D23609

Reviewers: grimar

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D24089

llvm-svn: 280284
This commit is contained in:
Rui Ueyama 2016-08-31 20:03:54 +00:00
parent 6c978aa9da
commit 95769b4a29
3 changed files with 34 additions and 13 deletions

View File

@ -653,6 +653,8 @@ private:
void readPhdrs();
void readSearchDir();
void readSections();
void readVersion();
void readVersionScriptCommand();
SymbolAssignment *readAssignment(StringRef Name);
OutputSectionCommand *readOutputSectionDescription(StringRef OutSec);
@ -676,7 +678,7 @@ private:
// For parsing version script.
void readExtern(std::vector<SymbolVersion> *Globals);
void readVersion(StringRef VerStr);
void readVersionDeclaration(StringRef VerStr);
void readGlobal(StringRef VerStr);
void readLocal();
@ -698,29 +700,39 @@ const StringMap<elf::ScriptParser::Handler> elf::ScriptParser::Cmd = {
{"PHDRS", &ScriptParser::readPhdrs},
{"SEARCH_DIR", &ScriptParser::readSearchDir},
{"SECTIONS", &ScriptParser::readSections},
{"VERSION", &ScriptParser::readVersion},
{";", &ScriptParser::readNothing}};
void ScriptParser::readVersionScript() {
StringRef Msg = "anonymous version definition is used in "
"combination with other version definitions";
readVersionScriptCommand();
if (!atEOF())
setError("EOF expected, but got " + next());
}
void ScriptParser::readVersionScriptCommand() {
if (skip("{")) {
readVersion("");
if (!atEOF())
setError(Msg);
readVersionDeclaration("");
return;
}
while (!atEOF() && !Error) {
while (!atEOF() && !Error && peek() != "}") {
StringRef VerStr = next();
if (VerStr == "{") {
setError(Msg);
setError("anonymous version definition is used in "
"combination with other version definitions");
return;
}
expect("{");
readVersion(VerStr);
readVersionDeclaration(VerStr);
}
}
void ScriptParser::readVersion() {
expect("{");
readVersionScriptCommand();
expect("}");
}
void ScriptParser::readLinkerScript() {
while (!atEOF()) {
StringRef Tok = next();
@ -1377,7 +1389,7 @@ unsigned ScriptParser::readPhdrType() {
return Ret;
}
void ScriptParser::readVersion(StringRef VerStr) {
void ScriptParser::readVersionDeclaration(StringRef VerStr) {
// Identifiers start at 2 because 0 and 1 are reserved
// for VER_NDX_LOCAL and VER_NDX_GLOBAL constants.
size_t VersionId = Config->VersionDefinitions.size() + 2;

View File

@ -101,6 +101,14 @@
# MAIN-NEXT: SHT_GNU_verdef {
# MAIN-NEXT: }
# RUN: echo "VERSION { \
# RUN: LIBSAMPLE_1.0 { global: a; local: *; }; \
# RUN: LIBSAMPLE_2.0 { global: b; local: *; }; \
# RUN: LIBSAMPLE_3.0 { global: c; local: *; }; \
# RUN: }" > %t.script
# RUN: ld.lld --script %t.script -shared -soname shared %t.o -o %t2.so
# RUN: llvm-readobj -V -dyn-symbols %t2.so | FileCheck --check-prefix=DSO %s
.globl a
.type a,@function
a:

View File

@ -35,8 +35,8 @@
# RUN: global: foo3; \
# RUN: local: *; }; " > %t5.script
# RUN: not ld.lld --version-script %t5.script -shared %t.o %t2.so -o %t5.so 2>&1 | \
# RUN: FileCheck -check-prefix=ERR %s
# ERR: anonymous version definition is used in combination with other version definitions
# RUN: FileCheck -check-prefix=ERR1 %s
# ERR1: anonymous version definition is used in combination with other version definitions
# RUN: echo "{ \
# RUN: global: foo1; \
@ -45,7 +45,8 @@
# RUN: global: foo3; \
# RUN: local: *; }; " > %t5.script
# RUN: not ld.lld --version-script %t5.script -shared %t.o %t2.so -o %t5.so 2>&1 | \
# RUN: FileCheck -check-prefix=ERR %s
# RUN: FileCheck -check-prefix=ERR2 %s
# ERR2: EOF expected, but got VERSION_2.0
# RUN: echo "VERSION_1.0{ \
# RUN: global: foo1; \