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 @@ -56,6 +56,7 @@ bool BsymbolicFunctions; bool BuildId; bool Demangle = true; + bool DynamicList; bool DisableVerify; bool DiscardAll; bool DiscardLocals; 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 @@ -9,6 +9,7 @@ #include "Driver.h" #include "Config.h" +#include "DynamicList.h" #include "Error.h" #include "ICF.h" #include "InputFiles.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); + Config->DynamicList = Args.hasArg(OPT_dynamic_list); + if (Config->DynamicList) + readDynamicList(getString(Args, OPT_dynamic_list)); 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,42 @@ +//===- 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; +}; + +extern DynamicList *DynList; + +} // namespace elf +} // namespace lld + +#endif Index: ELF/DynamicList.cpp =================================================================== --- /dev/null +++ ELF/DynamicList.cpp @@ -0,0 +1,131 @@ +//===- 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 "Config.h" +#include "Driver.h" +#include "ScriptParser.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. + StringRef Entry = next(); + if (Entry == "extern") { + StringRef Tok = peek(); + // And 'extern' itself can be used a symbol name. + if (Tok == ";") { + DynList->ExactMatch.insert(Entry); + } 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 { + DynList->ExactMatch.insert(Entry); + } +} + +void DynamicListParser::run() { + while (!atEOF()) { + readGroup(); + } +} + +void DynamicList::read(MemoryBufferRef MB) { + DynamicListParser(MB.getBuffer()).run(); +} + +bool DynamicList::isInDynamicList(StringRef Symbol) { + if (ExactMatch.find(Symbol) != ExactMatch.end()) + return true; + return false; +} Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -152,6 +152,9 @@ def z : JoinedOrSeparate<["-"], "z">, MetaVarName<"