From 717677af35b2a6a69242f337880923734ab4c67f Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Thu, 11 Feb 2016 21:17:59 +0000 Subject: [PATCH] ELF: Create LinkerScript class to move code out of Writer. Previously, we had code for linker scripts in Writer. This patch separates that as LinkerScript class. The class provides a few functions to query linker scripts and is also a container of some linker-script-specific information. Hopefully, Writer will only implement the default behavior and let the new class handle gotchas regarding linker scripts. llvm-svn: 260591 --- lld/ELF/Config.h | 1 - lld/ELF/Driver.cpp | 4 +++ lld/ELF/LinkerScript.cpp | 82 +++++++++++++++++++++++++++++++----------------- lld/ELF/LinkerScript.h | 45 ++++++++++++++++++++++++++ lld/ELF/Writer.cpp | 47 ++++++++------------------- 5 files changed, 115 insertions(+), 64 deletions(-) create mode 100644 lld/ELF/LinkerScript.h diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 6571807..f767dc3 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -48,7 +48,6 @@ struct Configuration { llvm::StringRef SoName; llvm::StringRef Sysroot; std::string RPath; - llvm::MapVector> OutputSections; std::vector SearchPaths; std::vector Undefined; bool AllowMultipleDefinition; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 9a14228..a58a7c4 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -11,6 +11,7 @@ #include "Config.h" #include "Error.h" #include "InputFiles.h" +#include "LinkerScript.h" #include "SymbolTable.h" #include "Target.h" #include "Writer.h" @@ -34,8 +35,10 @@ bool elf2::link(ArrayRef Args, raw_ostream &Error) { ErrorOS = &Error; Configuration C; LinkerDriver D; + LinkerScript LS; Config = &C; Driver = &D; + Script = &LS; Driver->main(Args.slice(1)); return !HasError; } @@ -292,6 +295,7 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { template void LinkerDriver::link(opt::InputArgList &Args) { SymbolTable Symtab; Target.reset(createTarget()); + Script->finalize(); if (!Config->Shared) { // Add entry symbol. diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 7e0ed34..536109f 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -13,6 +13,7 @@ // //===----------------------------------------------------------------------===// +#include "LinkerScript.h" #include "Config.h" #include "Driver.h" #include "SymbolTable.h" @@ -25,10 +26,36 @@ using namespace llvm; using namespace lld; using namespace lld::elf2; -namespace { -class LinkerScript { +LinkerScript *elf2::Script; + +void LinkerScript::finalize() { + for (const std::pair> &P : Sections) + for (StringRef S : P.second) + RevSections[S] = P.first; +} + +StringRef LinkerScript::getOutputSection(StringRef S) { + return RevSections.lookup(S); +} + +bool LinkerScript::isDiscarded(StringRef S) { + return RevSections.lookup(S) == "/DISCARD/"; +} + +int LinkerScript::compareSections(StringRef A, StringRef B) { + auto I = Sections.find(A); + auto E = Sections.end(); + if (I == E) + return 0; + auto J = Sections.find(B); + if (J == E) + return 0; + return I < J ? -1 : 1; +} + +class elf2::ScriptParser { public: - LinkerScript(BumpPtrAllocator *A, StringRef S, bool B) + ScriptParser(BumpPtrAllocator *A, StringRef S, bool B) : Saver(*A), Tokens(tokenize(S)), IsUnderSysroot(B) {} void run(); @@ -62,9 +89,8 @@ private: size_t Pos = 0; bool IsUnderSysroot; }; -} -void LinkerScript::run() { +void ScriptParser::run() { while (!atEOF()) { StringRef Tok = next(); if (Tok == ";") @@ -95,7 +121,7 @@ void LinkerScript::run() { } // We don't want to record cascading errors. Keep only the first one. -void LinkerScript::setError(const Twine &Msg) { +void ScriptParser::setError(const Twine &Msg) { if (Error) return; error(Msg); @@ -103,7 +129,7 @@ void LinkerScript::setError(const Twine &Msg) { } // Split S into linker script tokens. -std::vector LinkerScript::tokenize(StringRef S) { +std::vector ScriptParser::tokenize(StringRef S) { std::vector Ret; for (;;) { S = skipSpace(S); @@ -136,7 +162,7 @@ std::vector LinkerScript::tokenize(StringRef S) { } // Skip leading whitespace characters or /**/-style comments. -StringRef LinkerScript::skipSpace(StringRef S) { +StringRef ScriptParser::skipSpace(StringRef S) { for (;;) { if (S.startswith("/*")) { size_t E = S.find("*/", 2); @@ -155,9 +181,9 @@ StringRef LinkerScript::skipSpace(StringRef S) { } // An errneous token is handled as if it were the last token before EOF. -bool LinkerScript::atEOF() { return Error || Tokens.size() == Pos; } +bool ScriptParser::atEOF() { return Error || Tokens.size() == Pos; } -StringRef LinkerScript::next() { +StringRef ScriptParser::next() { if (Error) return ""; if (atEOF()) { @@ -167,7 +193,7 @@ StringRef LinkerScript::next() { return Tokens[Pos++]; } -bool LinkerScript::skip(StringRef Tok) { +bool ScriptParser::skip(StringRef Tok) { if (Error) return false; if (atEOF()) { @@ -180,7 +206,7 @@ bool LinkerScript::skip(StringRef Tok) { return true; } -void LinkerScript::expect(StringRef Expect) { +void ScriptParser::expect(StringRef Expect) { if (Error) return; StringRef Tok = next(); @@ -188,7 +214,7 @@ void LinkerScript::expect(StringRef Expect) { setError(Expect + " expected, but got " + Tok); } -void LinkerScript::addFile(StringRef S) { +void ScriptParser::addFile(StringRef S) { if (IsUnderSysroot && S.startswith("/")) { SmallString<128> Path; (Config->Sysroot + S).toStringRef(Path); @@ -218,7 +244,7 @@ void LinkerScript::addFile(StringRef S) { } } -void LinkerScript::readAsNeeded() { +void ScriptParser::readAsNeeded() { expect("("); bool Orig = Config->AsNeeded; Config->AsNeeded = true; @@ -231,7 +257,7 @@ void LinkerScript::readAsNeeded() { Config->AsNeeded = Orig; } -void LinkerScript::readEntry() { +void ScriptParser::readEntry() { // -e takes predecence over ENTRY(). expect("("); StringRef Tok = next(); @@ -240,7 +266,7 @@ void LinkerScript::readEntry() { expect(")"); } -void LinkerScript::readExtern() { +void ScriptParser::readExtern() { expect("("); while (!Error) { StringRef Tok = next(); @@ -250,7 +276,7 @@ void LinkerScript::readExtern() { } } -void LinkerScript::readGroup() { +void ScriptParser::readGroup() { expect("("); while (!Error) { StringRef Tok = next(); @@ -264,7 +290,7 @@ void LinkerScript::readGroup() { } } -void LinkerScript::readInclude() { +void ScriptParser::readInclude() { StringRef Tok = next(); auto MBOrErr = MemoryBuffer::getFile(Tok); if (!MBOrErr) { @@ -277,7 +303,7 @@ void LinkerScript::readInclude() { Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end()); } -void LinkerScript::readOutput() { +void ScriptParser::readOutput() { // -o takes predecence over OUTPUT(). expect("("); StringRef Tok = next(); @@ -286,14 +312,14 @@ void LinkerScript::readOutput() { expect(")"); } -void LinkerScript::readOutputArch() { +void ScriptParser::readOutputArch() { // Error checking only for now. expect("("); next(); expect(")"); } -void LinkerScript::readOutputFormat() { +void ScriptParser::readOutputFormat() { // Error checking only for now. expect("("); next(); @@ -310,29 +336,27 @@ void LinkerScript::readOutputFormat() { expect(")"); } -void LinkerScript::readSearchDir() { +void ScriptParser::readSearchDir() { expect("("); Config->SearchPaths.push_back(next()); expect(")"); } -void LinkerScript::readSections() { +void ScriptParser::readSections() { expect("{"); while (!Error && !skip("}")) readOutputSectionDescription(); } -void LinkerScript::readOutputSectionDescription() { - StringRef Name = next(); - std::vector &InputSections = Config->OutputSections[Name]; - +void ScriptParser::readOutputSectionDescription() { + std::vector &V = Script->Sections[next()]; expect(":"); expect("{"); while (!Error && !skip("}")) { next(); // Skip input file name. expect("("); while (!Error && !skip(")")) - InputSections.push_back(next()); + V.push_back(next()); } } @@ -348,5 +372,5 @@ static bool isUnderSysroot(StringRef Path) { // Entry point. The other functions or classes are private to this file. void elf2::readLinkerScript(BumpPtrAllocator *A, MemoryBufferRef MB) { StringRef Path = MB.getBufferIdentifier(); - LinkerScript(A, MB.getBuffer(), isUnderSysroot(Path)).run(); + ScriptParser(A, MB.getBuffer(), isUnderSysroot(Path)).run(); } diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h new file mode 100644 index 0000000..61ad5946 --- /dev/null +++ b/lld/ELF/LinkerScript.h @@ -0,0 +1,45 @@ +//===- LinkerScript.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_LINKER_SCRIPT_H +#define LLD_ELF_LINKER_SCRIPT_H + +#include "lld/Core/LLVM.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/MapVector.h" + +namespace lld { +namespace elf2 { + +class ScriptParser; + +class LinkerScript { + friend class ScriptParser; + +public: + StringRef getOutputSection(StringRef InputSection); + bool isDiscarded(StringRef InputSection); + int compareSections(StringRef A, StringRef B); + void finalize(); + +private: + // Map for SECTIONS command. The key is output section name + // and a value is a list of input section names. + llvm::MapVector> Sections; + + // Inverse map of Sections. + llvm::DenseMap RevSections; +}; + +extern LinkerScript *Script; + +} // namespace elf2 +} // namespace lld + +#endif diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index cff2a5b..d96926a 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -9,6 +9,7 @@ #include "Writer.h" #include "Config.h" +#include "LinkerScript.h" #include "OutputSections.h" #include "SymbolTable.h" #include "Target.h" @@ -68,7 +69,6 @@ private: void scanRelocs(InputSectionBase &S, const Elf_Shdr &RelSec); void createPhdrs(); void assignAddresses(); - void buildSectionMap(); void fixAbsoluteSymbols(); bool openFile(); void writeHeader(); @@ -111,8 +111,6 @@ private: uintX_t FileSize; uintX_t SectionHeaderOff; - llvm::StringMap InputToOutputSection; - // Flag to force GOT to be in output if we have relocations // that relies on its address. bool HasGotOffRel = false; @@ -190,7 +188,6 @@ template void elf2::writeResult(SymbolTable *Symtab) { // The main function of the writer. template void Writer::run() { - buildSectionMap(); if (!Config->DiscardAll) copyLocalSymbols(); addReservedSymbols(); @@ -595,10 +592,14 @@ template static bool isRelroSection(OutputSectionBase *Sec) { // Output section ordering is determined by this function. template -static bool compareOutputSections(OutputSectionBase *A, - OutputSectionBase *B) { +static bool compareSections(OutputSectionBase *A, + OutputSectionBase *B) { typedef typename ELFFile::uintX_t uintX_t; + int Comp = Script->compareSections(A->getName(), B->getName()); + if (Comp != 0) + return Comp < 0; + uintX_t AFlags = A->getFlags(); uintX_t BFlags = B->getFlags(); @@ -721,9 +722,9 @@ void Writer::addCopyRelSymbols(std::vector *> &Syms) { template StringRef Writer::getOutputSectionName(StringRef S) const { - auto It = InputToOutputSection.find(S); - if (It != std::end(InputToOutputSection)) - return It->second; + StringRef Out = Script->getOutputSection(S); + if (!Out.empty()) + return Out; for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors."}) @@ -742,24 +743,9 @@ void reportDiscarded(InputSectionBase *IS, } template -bool Writer::isDiscarded(InputSectionBase *IS) const { - if (!IS || !IS->isLive() || IS == &InputSection::Discarded) - return true; - return InputToOutputSection.lookup(IS->getSectionName()) == "/DISCARD/"; -} - -template -static bool compareSections(OutputSectionBase *A, - OutputSectionBase *B) { - auto ItA = Config->OutputSections.find(A->getName()); - auto ItEnd = std::end(Config->OutputSections); - if (ItA == ItEnd) - return compareOutputSections(A, B); - auto ItB = Config->OutputSections.find(B->getName()); - if (ItB == ItEnd) - return compareOutputSections(A, B); - - return std::distance(ItA, ItB) > 0; +bool Writer::isDiscarded(InputSectionBase *S) const { + return !S || !S->isLive() || S == &InputSection::Discarded || + Script->isDiscarded(S->getSectionName()); } // The beginning and the ending of .rel[a].plt section are marked @@ -1487,13 +1473,6 @@ template void Writer::writeSections() { Sec->writeTo(Buf + Sec->getFileOff()); } -template void Writer::buildSectionMap() { - for (const std::pair> &OutSec : - Config->OutputSections) - for (StringRef Name : OutSec.second) - InputToOutputSection[Name] = OutSec.first; -} - template void elf2::writeResult(SymbolTable *Symtab); template void elf2::writeResult(SymbolTable *Symtab); template void elf2::writeResult(SymbolTable *Symtab); -- 2.7.4