Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -626,7 +626,10 @@ ScriptParser(StringRef S, bool B) : ScriptParserBase(S), IsUnderSysroot(B) {} void readLinkerScript(); - void readVersionScript(); + + // Parses version script. Can parse version script file as well as VERSION + // command of linker script. Returns false if end of VESRION command was met. + bool readVersionScript(); private: void addFile(StringRef Path); @@ -643,6 +646,7 @@ void readPhdrs(); void readSearchDir(); void readSections(); + void readVersion(); SymbolAssignment *readAssignment(StringRef Name); OutputSectionCommand *readOutputSectionDescription(StringRef OutSec); @@ -666,7 +670,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,27 +692,37 @@ {"PHDRS", &ScriptParser::readPhdrs}, {"SEARCH_DIR", &ScriptParser::readSearchDir}, {"SECTIONS", &ScriptParser::readSections}, + {"VERSION", &ScriptParser::readVersion}, {";", &ScriptParser::readNothing}}; -void ScriptParser::readVersionScript() { +bool ScriptParser::readVersionScript() { StringRef Msg = "anonymous version definition is used in " "combination with other version definitions"; if (skip("{")) { - readVersion(""); + readVersionDeclaration(""); if (!atEOF()) setError(Msg); - return; + return true; } while (!atEOF() && !Error) { + if (peek() == "}") + return false; StringRef VerStr = next(); if (VerStr == "{") { setError(Msg); - return; + return true; } expect("{"); - readVersion(VerStr); + readVersionDeclaration(VerStr); } + return true; +} + +void ScriptParser::readVersion() { + expect("{"); + readVersionScript(); + expect("}"); } void ScriptParser::readLinkerScript() { @@ -1363,7 +1377,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; @@ -1440,7 +1454,8 @@ } void elf::readVersionScript(MemoryBufferRef MB) { - ScriptParser(MB.getBuffer(), false).readVersionScript(); + if (!ScriptParser(MB.getBuffer(), false).readVersionScript()) + error("unexpected end of version script file"); } template class elf::LinkerScript; Index: test/ELF/verdef.s =================================================================== --- test/ELF/verdef.s +++ test/ELF/verdef.s @@ -101,6 +101,19 @@ # MAIN-NEXT: SHT_GNU_verdef { # MAIN-NEXT: } +# RUN: echo "VERSION { \ +# RUN: LIBSAMPLE_1.0{ \ +# RUN: global: a; \ +# RUN: local: *; }; \ +# RUN: LIBSAMPLE_2.0{ \ +# RUN: global: b; \ +# RUN: local: *; }; \ +# RUN: LIBSAMPLE_3.0{ \ +# RUN: global: c; \ +# RUN: local: *; }; }" > %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: