Index: ELF/CMakeLists.txt =================================================================== --- ELF/CMakeLists.txt +++ ELF/CMakeLists.txt @@ -5,6 +5,7 @@ add_lld_library(lldELF Driver.cpp DriverUtils.cpp + DynamicList.cpp Error.cpp ICF.cpp InputFiles.cpp Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -50,6 +50,7 @@ std::string RPath; std::vector SearchPaths; std::vector Undefined; + std::vector DynamicList; bool AllowMultipleDefinition; bool AsNeeded = false; bool Bsymbolic; Index: ELF/Driver.h =================================================================== --- ELF/Driver.h +++ ELF/Driver.h @@ -30,6 +30,7 @@ private: std::vector getArchiveMembers(MemoryBufferRef MB); void readConfigs(llvm::opt::InputArgList &Args); + void readDynamicList(StringRef Path); void createFiles(llvm::opt::InputArgList &Args); template void link(llvm::opt::InputArgList &Args); Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -16,6 +16,7 @@ #include "SymbolTable.h" #include "Target.h" #include "Writer.h" +#include "DynamicList.h" #include "lld/Driver/Driver.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/TargetSelect.h" @@ -38,9 +39,11 @@ Configuration C; LinkerDriver D; LinkerScript LS; + DynamicList DL; Config = &C; Driver = &D; Script = &LS; + DynList = &DL; Driver->main(Args); return !HasError; } @@ -133,6 +136,19 @@ } } +void LinkerDriver::readDynamicList(StringRef Path) { + using namespace llvm::sys::fs; + auto MBOrErr = MemoryBuffer::getFile(Path); + if (!MBOrErr) { + error(MBOrErr, "cannot open " + Path); + return; + } + std::unique_ptr &MB = *MBOrErr; + MemoryBufferRef MBRef = MB->getMemBufferRef(); + OwningMBs.push_back(std::move(MB)); // take MB ownership + DynList->read(MBRef); +} + // Add a given library by searching it from input search paths. void LinkerDriver::addLibrary(StringRef Name) { std::string Path = searchLibrary(Name); @@ -299,6 +315,9 @@ Config->OutputFile = getString(Args, OPT_o); Config->SoName = getString(Args, OPT_soname); Config->Sysroot = getString(Args, OPT_sysroot); + StringRef DynamicListPath = getString(Args, OPT_dynamic_list); + if (!DynamicListPath.empty()) + readDynamicList(DynamicListPath); Config->Optimize = getInteger(Args, OPT_O, 0); Config->LtoO = getInteger(Args, OPT_lto_O, 2); Index: ELF/DynamicList.h =================================================================== --- /dev/null +++ ELF/DynamicList.h @@ -0,0 +1,49 @@ +//===- DynamicList.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_DYNAMIC_LIST_H +#define LLD_ELF_DYNAMIC_LIST_H + +#include "lld/Core/LLVM.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/MemoryBuffer.h" + +namespace lld { +namespace elf { + +class DynamicListParser; + +class DynamicList { + friend class DynamicListParser; + +public: + void read(MemoryBufferRef MB); + + bool isInDynamicList(StringRef Symbol); + +private: + enum GlobLanguage { + LANGUAGE_C, + LANGUAGE_CXX, + LANGUAGE_NOT_SUPPORTED + }; + + llvm::StringSet<> ExactMatch; + std::vector> GlobSymbols; + + llvm::BumpPtrAllocator Alloc; +}; + +extern DynamicList *DynList; + +} // namespace elf +} // namespace lld + +#endif Index: ELF/DynamicList.cpp =================================================================== --- /dev/null +++ ELF/DynamicList.cpp @@ -0,0 +1,153 @@ +//===- LinkerScript.cpp ---------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the parser/evaluator of the linker script. +// It does not construct an AST but consume linker script directives directly. +// Results are written to Driver or Config object. +// +//===----------------------------------------------------------------------===// + +#include "DynamicList.h" +#include "ScriptParser.h" +#include "Config.h" +#include "Driver.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/StringSaver.h" + +using namespace llvm; +using namespace llvm::object; +using namespace lld; +using namespace lld::elf; + +DynamicList *elf::DynList; + +// Parse the --dynamic-list argument. A dynamic list is in the form +// +// { symbol1; symbol2; extern "C++" { symbol3; namespace::symbol4 }; } +// +// With the ';' after symbol4 being optional. Multiple groups can be +// defined in the same file and they are merged in only one definition. + +class elf::DynamicListParser final : public ScriptParserBase { +public: + DynamicListParser(StringRef S) : ScriptParserBase(S) {} + + void run() final; + +private: + void readGroup(); + void readLanguageGroup(DynamicList::GlobLanguage); + void readEntry(DynamicList::GlobLanguage); + DynamicList::GlobLanguage SupportedLanguage(StringRef Lang); +}; + +// Returns if the language defined inside quotes with extern keyword is +// supported (currently only 'C++'). +DynamicList::GlobLanguage +DynamicListParser::SupportedLanguage(StringRef Lang) { + if (Lang == "C++") + return DynamicList::LANGUAGE_CXX; + return DynamicList::LANGUAGE_NOT_SUPPORTED; +} + +// Parses the groups defined by 'export 'LANG' { ... }'. For such symbols +// the language defined is used to mark with demangle to use in the match +// function. +void DynamicListParser::readLanguageGroup(DynamicList::GlobLanguage Lang) { + expect("{"); + while (!Error) { + readEntry(Lang); + StringRef Tok = peek(); + if (Tok == "}") { + next(); + break; + } + expect(";"); + if (peek() == "}") { + next(); + break; + } + } +} + +// Parse the default group definition using C language symbol name. +void DynamicListParser::readGroup() { + expect("{"); + while (!Error) { + readEntry(DynamicList::LANGUAGE_C); + expect(";"); + if (peek() == "}") { + next(); + break; + } + } + expect(";"); +} + +void DynamicListParser::readEntry(DynamicList::GlobLanguage Lang) { + // An entry may specify the language it should bind with. For instance: + // - extern "C++" { namespace::sym }; + // It instructs the demangled symbol 'sym' should be exported as well. + Token Entry = next(); + if (Entry == "extern") { + StringRef Tok = peek(); + // And 'extern' itself can be used a symbol name. + if (Tok == ";") { + DynList->ExactMatch.insert(Entry.Value); + } else { + StringRef Tok = next(); + DynamicList::GlobLanguage Lang = SupportedLanguage(Tok); + if (Lang != DynamicList::LANGUAGE_NOT_SUPPORTED) + readLanguageGroup(Lang); + else + setError("invalid language in extern definition (" + Tok + ")"); + } + } else { + if (Entry.Quoted) + DynList->ExactMatch.insert(Entry.Value); + else + DynList->GlobSymbols.push_back(std::make_pair(Entry.Value, Lang)); + } +} + +void DynamicListParser::run() { + while (!atEOF()) { + readGroup(); + } +} + +void DynamicList::read(MemoryBufferRef MB) { + DynamicListParser(MB.getBuffer()).run(); +} + +bool DynamicList::isInDynamicList(StringRef Symbol) { + // To avoid applying the matchStr algorithm on every entry, for quoted + // strings (which means exact match even with wildcards characteres) a + // StringSet map is created and it is consulted before matching the + // glob patterns. + if (ExactMatch.find(Symbol) != ExactMatch.end()) + return true; + + // For any other entry check each glob entry with language defined + // entries (for instance 'extern C++') being demangled first. + for (auto entry : GlobSymbols) { + if (entry.second == LANGUAGE_C) { + if (matchGlobStr(entry.first, Symbol)) + return true; + } else if (entry.second == LANGUAGE_CXX) { + std::string NameToMatch = demangle(Symbol); + if (matchGlobStr(entry.first, NameToMatch)) + return true; + } + } + + return false; +} Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -74,32 +74,8 @@ return I < J ? -1 : 1; } -// Returns true if S matches T. S can contain glob meta-characters. -// The asterisk ('*') matches zero or more characacters, and the question -// mark ('?') matches one character. -static bool matchStr(StringRef S, StringRef T) { - for (;;) { - if (S.empty()) - return T.empty(); - if (S[0] == '*') { - S = S.substr(1); - if (S.empty()) - // Fast path. If a pattern is '*', it matches anything. - return true; - for (size_t I = 0, E = T.size(); I < E; ++I) - if (matchStr(S, T.substr(I))) - return true; - return false; - } - if (T.empty() || (S[0] != T[0] && S[0] != '?')) - return false; - S = S.substr(1); - T = T.substr(1); - } -} - template bool SectionRule::match(InputSectionBase *S) { - return matchStr(SectionPattern, S->getSectionName()); + return matchGlobStr(SectionPattern, S->getSectionName()); } class elf::ScriptParser final : public elf::ScriptParserBase { @@ -244,7 +220,7 @@ } std::unique_ptr &MB = *MBOrErr; StringRef S = Saver.save(MB->getMemBufferRef().getBuffer()); - std::vector V = tokenize(S); + std::vector V = tokenize(S); Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end()); } Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -152,6 +152,9 @@ def z : JoinedOrSeparate<["-"], "z">, MetaVarName<"