Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -643,6 +643,8 @@ void readPhdrs(); void readSearchDir(); void readSections(); + void readVersion(); + void readVersionScriptCommand(); SymbolAssignment *readAssignment(StringRef Name); OutputSectionCommand *readOutputSectionDescription(StringRef OutSec); @@ -666,7 +668,7 @@ // For parsing version script. void readExtern(std::vector *Globals); - void readVersion(StringRef VerStr); + void readVersionDeclaration(StringRef VerStr); void readGlobal(StringRef VerStr); void readLocal(); @@ -688,29 +690,39 @@ {"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(); @@ -1363,7 +1375,7 @@ 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; Index: test/ELF/verdef.s =================================================================== --- test/ELF/verdef.s +++ test/ELF/verdef.s @@ -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: Index: test/ELF/version-script.s =================================================================== --- test/ELF/version-script.s +++ test/ELF/version-script.s @@ -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; \