Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -25,6 +25,7 @@ #include "ScriptParser.h" #include "Strings.h" #include "Symbols.h" +#include "SymbolListFile.h" #include "SymbolTable.h" #include "Target.h" #include "Writer.h" @@ -609,6 +610,7 @@ void readPhdrs(); void readSearchDir(); void readSections(); + void readVersion(); SymbolAssignment *readAssignment(StringRef Name); OutputSectionCommand *readOutputSectionDescription(StringRef OutSec); @@ -649,6 +651,7 @@ {"PHDRS", &ScriptParser::readPhdrs}, {"SEARCH_DIR", &ScriptParser::readSearchDir}, {"SECTIONS", &ScriptParser::readSections}, + {"VERSION", &ScriptParser::readVersion}, {";", &ScriptParser::readNothing}}; void ScriptParser::run() { @@ -735,8 +738,7 @@ } std::unique_ptr &MB = *MBOrErr; StringRef S = Saver.save(MB->getMemBufferRef().getBuffer()); - std::vector V = tokenize(S); - Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end()); + ScriptParser(S, IsUnderSysroot).run(); } void ScriptParser::readOutput() { @@ -822,6 +824,12 @@ } } +void ScriptParser::readVersion() { + expect("{"); + Pos += parseVersionScript(Input, Pos, Tokens); + expect("}"); +} + static int precedence(StringRef Op) { return StringSwitch(Op) .Case("*", 4) Index: ELF/ScriptParser.h =================================================================== --- ELF/ScriptParser.h +++ ELF/ScriptParser.h @@ -11,6 +11,7 @@ #define LLD_ELF_SCRIPT_PARSER_H #include "lld/Core/LLVM.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include #include @@ -20,7 +21,11 @@ class ScriptParserBase { public: - explicit ScriptParserBase(StringRef S) : Input(S), Tokens(tokenize(S)) {} + explicit ScriptParserBase(StringRef S) + : Input(S), TokensHolder(tokenize(S)), Tokens(TokensHolder) {} + + explicit ScriptParserBase(StringRef S, size_t Pos, ArrayRef Tokens) + : Input(S), Pos(Pos), Tokens(Tokens) {} protected: void setError(const Twine &Msg); @@ -36,7 +41,8 @@ void printErrorPos(); StringRef Input; - std::vector Tokens; + std::vector TokensHolder; + ArrayRef Tokens; size_t Pos = 0; bool Error = false; }; Index: ELF/SymbolListFile.h =================================================================== --- ELF/SymbolListFile.h +++ ELF/SymbolListFile.h @@ -20,6 +20,7 @@ void parseDynamicList(MemoryBufferRef MB); void parseVersionScript(MemoryBufferRef MB); +size_t parseVersionScript(StringRef S, size_t Pos, ArrayRef Tokens); } // namespace elf } // namespace lld Index: ELF/SymbolListFile.cpp =================================================================== --- ELF/SymbolListFile.cpp +++ ELF/SymbolListFile.cpp @@ -69,7 +69,10 @@ public: VersionScriptParser(StringRef S) : ScriptParserBase(S) {} - void run(); + VersionScriptParser(StringRef S, size_t Pos, ArrayRef Tokens) + : ScriptParserBase(S, Pos, Tokens) {} + + size_t run(); private: void parseExtern(std::vector *Globals); @@ -146,27 +149,41 @@ } } -void VersionScriptParser::run() { +size_t VersionScriptParser::run() { + size_t Begin = Pos; + StringRef Msg = "anonymous version definition is used in " "combination with other version definitions"; if (skip("{")) { parseVersion(""); if (!atEOF()) setError(Msg); - return; + return Pos - Begin; } while (!atEOF() && !Error) { + // If this script is inside VERSION command of linkerscript, + // we should just exit here and let linker script parser continue. + if (TokensHolder.empty() && peek() == "}") + return Pos - Begin; + StringRef VerStr = next(); if (VerStr == "{") { setError(Msg); - return; + return 0; } expect("{"); parseVersion(VerStr); } + + return Pos - Begin; } void elf::parseVersionScript(MemoryBufferRef MB) { VersionScriptParser(MB.getBuffer()).run(); } + +size_t elf::parseVersionScript(StringRef S, size_t Pos, + ArrayRef Tokens) { + return VersionScriptParser(S, Pos, Tokens).run(); +} 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: