Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -10,11 +10,13 @@ #ifndef LLD_ELF_LINKER_SCRIPT_H #define LLD_ELF_LINKER_SCRIPT_H +#include "ScriptParser.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/MemoryBuffer.h" +#include namespace lld { namespace elf { @@ -24,48 +26,19 @@ void readLinkerScript(MemoryBufferRef MB); class ScriptParser; +class LayoutParser; template class InputSectionBase; +template class ObjectFile; template class OutputSectionBase; - -// This class represents each rule in SECTIONS command. -struct SectionRule { - SectionRule(StringRef D, StringRef S) - : Dest(D), SectionPattern(S) {} - - StringRef Dest; - - StringRef SectionPattern; -}; - -// This enum represents what we can observe in SECTIONS tag of script: -// ExprKind is a location counter change, like ". = . + 0x1000" -// SectionKind is a description of output section, like ".data :..." -enum SectionsCommandKind { ExprKind, SectionKind }; - -struct SectionsCommand { - SectionsCommandKind Kind; - std::vector Expr; - StringRef SectionName; -}; +template class OutputSectionFactory; +template class SymbolTable; // ScriptConfiguration holds linker script parse results. struct ScriptConfiguration { - // SECTIONS commands. - std::vector Sections; - - // Section fill attribute for each section. - llvm::StringMap> Filler; - - // Used to assign addresses to sections. - std::vector Commands; - bool DoLayout = false; + StringRef SectionsData; llvm::BumpPtrAllocator Alloc; - - // List of section patterns specified with KEEP commands. They will - // be kept even if they are unused and --gc-sections is specified. - std::vector KeptSections; }; extern ScriptConfiguration *ScriptConfig; @@ -75,19 +48,19 @@ typedef typename ELFT::uint uintX_t; public: - StringRef getOutputSection(InputSectionBase *S); - ArrayRef getFiller(StringRef Name); - bool isDiscarded(InputSectionBase *S); - bool shouldKeep(InputSectionBase *S); void assignAddresses(ArrayRef *> S); - int compareSections(StringRef A, StringRef B); + + std::vector *> + createSections(OutputSectionFactory &Factory, + SymbolTable &SymTab); + + void checkLive(std::vector *> &Sec, + std::function *)> MarkFn); private: // "ScriptConfig" is a bit too long, so define a short name for it. ScriptConfiguration &Opt = *ScriptConfig; - int getSectionIndex(StringRef Name); - uintX_t Dot; }; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -20,6 +20,7 @@ #include "OutputSections.h" #include "ScriptParser.h" #include "SymbolTable.h" +#include "Writer.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ELF.h" #include "llvm/Support/FileSystem.h" @@ -44,7 +45,7 @@ namespace { class ExprParser : public ScriptParserBase { public: - ExprParser(std::vector &Tokens, uint64_t Dot) + ExprParser(const std::vector &Tokens, uint64_t Dot) : ScriptParserBase(Tokens), Dot(Dot) {} uint64_t run(); @@ -76,7 +77,7 @@ .Default(-1); } -static uint64_t evalExpr(std::vector &Tokens, uint64_t Dot) { +static uint64_t evalExpr(const std::vector &Tokens, uint64_t Dot) { return ExprParser(Tokens, Dot).run(); } @@ -186,27 +187,6 @@ uint64_t ExprParser::parseExpr() { return parseExpr1(parsePrimary(), 0); } template -StringRef LinkerScript::getOutputSection(InputSectionBase *S) { - for (SectionRule &R : Opt.Sections) - if (matchStr(R.SectionPattern, S->getSectionName())) - return R.Dest; - return ""; -} - -template -bool LinkerScript::isDiscarded(InputSectionBase *S) { - return getOutputSection(S) == "/DISCARD/"; -} - -template -bool LinkerScript::shouldKeep(InputSectionBase *S) { - for (StringRef Pat : Opt.KeptSections) - if (matchStr(Pat, S->getSectionName())) - return true; - return false; -} - -template static OutputSectionBase * findSection(ArrayRef *> V, StringRef Name) { for (OutputSectionBase *Sec : V) @@ -215,82 +195,242 @@ return nullptr; } +enum CommandKind { + ExprKind, + OutSectionKind, + InputSectionKind, + FillerKind, +}; + +struct Command { + CommandKind Kind; + std::vector Expr; + StringRef Name; + StringRef Pattern; + bool Keep; + std::vector Filler; + + static Command createExprCmd(std::vector &Expr) { + return Command{ExprKind, Expr, "", "", false, {}}; + } + static Command createOutSecCmd(StringRef Name) { + return Command{OutSectionKind, {}, Name, "", false, {}}; + } + static Command createInputSectionCmd(StringRef Pattern, bool Keep) { + return Command{InputSectionKind, {}, "", Pattern, Keep, {}}; + } + static Command createFillerCmd(std::vector &Filler) { + return Command{FillerKind, {}, "", "", false, std::move(Filler)}; + } +}; + +class elf::LayoutParser : public ScriptParserBase { + typedef std::function Callback; + +public: + LayoutParser() : ScriptParserBase(ScriptConfig->SectionsData) {} + + size_t run(Callback C) { + expect("SECTIONS"); + expect("{"); + while (!Error && !skip("}")) { + StringRef Tok = peek(); + if (Tok == ".") + parseLocationCounterValue(C); + else + parseOutputSectionDescription(C); + } + return Pos - 1; + } + +private: + void parseLocationCounterValue(Callback Call) { + expect("."); + expect("="); + + std::vector Expr; + while (!Error) { + StringRef Tok = next(); + if (Tok == ";") + break; + Expr.push_back(Tok); + } + if (Expr.empty()) + error("error in location counter expression"); + Call(Command::createExprCmd(Expr)); + } + + void parseOutputSectionDescription(Callback Call) { + StringRef OutSec = next(); + Call(Command::createOutSecCmd(OutSec)); + expect(":"); + expect("{"); + + while (!Error && !skip("}")) { + StringRef Tok = next(); + if (Tok == "*") { + expect("("); + while (!Error && !skip(")")) + Call(Command::createInputSectionCmd(next(), false)); + } else if (Tok == "KEEP") { + expect("("); + expect("*"); + expect("("); + while (!Error && !skip(")")) + Call(Command::createInputSectionCmd(next(), true)); + expect(")"); + } else { + setError("unknown command " + Tok); + } + } + + if (Error) + return; + + StringRef Tok = peek(); + std::vector Filler; + if (Tok.startswith("=")) { + if (!Tok.startswith("=0x")) { + setError("filler should be a hexadecimal value"); + return; + } + Tok = Tok.substr(3); + Filler = parseHex(Tok); + next(); + Call(Command::createFillerCmd(Filler)); + } + } +}; + template -void LinkerScript::assignAddresses( - ArrayRef *> Sections) { +static void addSection(OutputSectionFactory &Factory, + StringRef OutSecName, InputSectionBase *InSec, + std::vector *> &List) { + if (OutSecName == "/DISCARD/" || !InSec->Live) + return; + + OutputSectionBase *OutSection = nullptr; + bool IsNew; + std::tie(OutSection, IsNew) = Factory.create(InSec, OutSecName); + OutSection->addSection(InSec); + if (IsNew) + List.push_back(OutSection); +} + +template +std::vector *> +LinkerScript::createSections(OutputSectionFactory &Factory, + SymbolTable &Symtab) { + // Create a list of input sections that were not assigned to output yet. + std::vector *> Unassigned; + for (const std::unique_ptr> &F : + Symtab.getObjectFiles()) { + for (InputSectionBase *C : F->getSections()) + if (!isDiscarded(C)) + Unassigned.push_back(C); + } + + std::vector *> Sections; + StringRef OutSecName; + OutputSectionBase *OutSection = nullptr; + LayoutParser().run([&](const Command &Cmd) { + if (Cmd.Kind == OutSectionKind) { + OutSecName = Cmd.Name; + return; + } + if (OutSection && Cmd.Kind == FillerKind) { + OutSection->Filler = Cmd.Filler; + return; + } + + if (Cmd.Kind != InputSectionKind) + return; + + auto I = std::find_if(Unassigned.begin(), Unassigned.end(), + [&](InputSectionBase *S) { + return matchStr(Cmd.Pattern, S->getSectionName()); + }); + if (I == Unassigned.end()) + return; + + InputSectionBase *InSec = *I; + Unassigned.erase(I); + addSection(Factory, OutSecName, InSec, Sections); + }); + // Orphan sections are sections present in the input files which // are not explicitly placed into the output file by the linker script. // We place orphan sections at end of file. // Other linkers places them using some heuristics as described in // https://sourceware.org/binutils/docs/ld/Orphan-Sections.html#Orphan-Sections. - for (OutputSectionBase *Sec : Sections) { - StringRef Name = Sec->getName(); - if (getSectionIndex(Name) == INT_MAX) - Opt.Commands.push_back({SectionKind, {}, Name}); - } + for (InputSectionBase *U : Unassigned) + addSection(Factory, getOutputSectionName(U), U, Sections); + + return Sections; +} +template +void LinkerScript::assignAddresses( + ArrayRef *> Sections) { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = Out::ElfHeader->getSize() + Out::ProgramHeaders->getSize(); uintX_t ThreadBssOffset = 0; - for (SectionsCommand &Cmd : Opt.Commands) { - if (Cmd.Kind == ExprKind) { - Dot = evalExpr(Cmd.Expr, Dot); - continue; - } - - OutputSectionBase *Sec = findSection(Sections, Cmd.SectionName); + DenseSet *> Assigned; + auto Assign = [&](StringRef Name) { + OutputSectionBase *Sec = findSection(Sections, Name); if (!Sec) - continue; + return; if ((Sec->getFlags() & SHF_TLS) && Sec->getType() == SHT_NOBITS) { uintX_t TVA = Dot + ThreadBssOffset; TVA = alignTo(TVA, Sec->getAlign()); Sec->setVA(TVA); ThreadBssOffset = TVA - Dot + Sec->getSize(); - continue; + Assigned.insert(Sec); + return; } if (Sec->getFlags() & SHF_ALLOC) { Dot = alignTo(Dot, Sec->getAlign()); Sec->setVA(Dot); Dot += Sec->getSize(); - continue; + Assigned.insert(Sec); + return; } - } -} - -template -ArrayRef LinkerScript::getFiller(StringRef Name) { - auto I = Opt.Filler.find(Name); - if (I == Opt.Filler.end()) - return {}; - return I->second; -} + }; -// Returns the index of the given section name in linker script -// SECTIONS commands. Sections are laid out as the same order as they -// were in the script. If a given name did not appear in the script, -// it returns INT_MAX, so that it will be laid out at end of file. -template -int LinkerScript::getSectionIndex(StringRef Name) { - auto Begin = Opt.Commands.begin(); - auto End = Opt.Commands.end(); - auto I = std::find_if(Begin, End, [&](SectionsCommand &N) { - return N.Kind == SectionKind && N.SectionName == Name; + LayoutParser().run([&](const Command &Cmd) { + if (Cmd.Kind == ExprKind) { + Dot = evalExpr(Cmd.Expr, Dot); + return; + } + if (Cmd.Kind != OutSectionKind) + return; + Assign(Cmd.Name); }); - return I == End ? INT_MAX : (I - Begin); + + // Finally process all orphan sections. + for (OutputSectionBase *Sec : Sections) + if (!Assigned.count(Sec)) { + Assigned.insert(Sec); + Assign(Sec->getName()); + } } -// A compartor to sort output sections. Returns -1 or 1 if -// A or B are mentioned in linker script. Otherwise, returns 0. template -int LinkerScript::compareSections(StringRef A, StringRef B) { - int I = getSectionIndex(A); - int J = getSectionIndex(B); - if (I == INT_MAX && J == INT_MAX) - return 0; - return I < J ? -1 : 1; +void LinkerScript::checkLive( + std::vector *> &Sec, + std::function *)> MarkFn) { + LayoutParser().run([&](const Command &Cmd) { + if (Cmd.Kind != InputSectionKind) + return; + if (!Cmd.Keep) + return; + for (InputSectionBase *S : Sec) + if (matchStr(Cmd.Pattern, S->getSectionName())) + MarkFn(S); + }); } // Returns true if S matches T. S can contain glob meta-characters. @@ -338,10 +478,7 @@ void readOutputArch(); void readOutputFormat(); void readSearchDir(); - void readSections(); - - void readLocationCounterValue(); - void readOutputSectionDescription(); + void skipSections(); const static StringMap Cmd; ScriptConfiguration &Opt = *ScriptConfig; @@ -359,7 +496,7 @@ {"OUTPUT_ARCH", &ScriptParser::readOutputArch}, {"OUTPUT_FORMAT", &ScriptParser::readOutputFormat}, {"SEARCH_DIR", &ScriptParser::readSearchDir}, - {"SECTIONS", &ScriptParser::readSections}, + {"SECTIONS", &ScriptParser::skipSections}, {";", &ScriptParser::readNothing}}; void ScriptParser::run() { @@ -500,70 +637,12 @@ expect(")"); } -void ScriptParser::readSections() { +void ScriptParser::skipSections() { Opt.DoLayout = true; - expect("{"); - while (!Error && !skip("}")) { - StringRef Tok = peek(); - if (Tok == ".") - readLocationCounterValue(); - else - readOutputSectionDescription(); - } -} - -void ScriptParser::readLocationCounterValue() { - expect("."); - expect("="); - Opt.Commands.push_back({ExprKind, {}, ""}); - SectionsCommand &Cmd = Opt.Commands.back(); - while (!Error) { - StringRef Tok = next(); - if (Tok == ";") - break; - Cmd.Expr.push_back(Tok); - } - if (Cmd.Expr.empty()) - error("error in location counter expression"); -} - -void ScriptParser::readOutputSectionDescription() { - StringRef OutSec = next(); - Opt.Commands.push_back({SectionKind, {}, OutSec}); - expect(":"); - expect("{"); - - while (!Error && !skip("}")) { - StringRef Tok = next(); - if (Tok == "*") { - expect("("); - while (!Error && !skip(")")) - Opt.Sections.emplace_back(OutSec, next()); - } else if (Tok == "KEEP") { - expect("("); - expect("*"); - expect("("); - while (!Error && !skip(")")) { - StringRef Sec = next(); - Opt.Sections.emplace_back(OutSec, Sec); - Opt.KeptSections.push_back(Sec); - } - expect(")"); - } else { - setError("unknown command " + Tok); - } - } - - StringRef Tok = peek(); - if (Tok.startswith("=")) { - if (!Tok.startswith("=0x")) { - setError("filler should be a hexadecimal value"); - return; - } - Tok = Tok.substr(3); - Opt.Filler[OutSec] = parseHex(Tok); - next(); - } + Opt.SectionsData = Input.drop_front(Tokens[Pos - 1].begin() - Input.begin()); + // Do nothing, just update the Pos and also + // script validation check is performed during scan. + Pos += LayoutParser().run([](const Command &Arg) {}); } static bool isUnderSysroot(StringRef Path) { Index: ELF/MarkLive.cpp =================================================================== --- ELF/MarkLive.cpp +++ ELF/MarkLive.cpp @@ -173,6 +173,7 @@ // Preserve special sections and those which are specified in linker // script KEEP command. + std::vector *> KeepCandidate; for (const std::unique_ptr> &F : Symtab::X->getObjectFiles()) for (InputSectionBase *Sec : F->getSections()) @@ -182,10 +183,17 @@ // referred by .eh_frame here. if (auto *EH = dyn_cast_or_null>(Sec)) scanEhFrameSection(*EH); - if (isReserved(Sec) || Script::X->shouldKeep(Sec)) + if (isReserved(Sec)) Enqueue({Sec, 0}); + else if (ScriptConfig->DoLayout) + KeepCandidate.push_back(Sec); } + if (!KeepCandidate.empty()) + Script::X->checkLive(KeepCandidate, [&](InputSectionBase *K) { + Enqueue({K, 0}); + }); + // Mark all reachable sections. while (!Q.empty()) forEachSuccessor(Q.pop_back_val(), Enqueue); Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -13,6 +13,7 @@ #include "Config.h" #include "lld/Core/LLVM.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELF.h" @@ -97,6 +98,8 @@ virtual void writeTo(uint8_t *Buf) {} virtual ~OutputSectionBase() = default; + std::vector Filler; + protected: StringRef Name; Elf_Shdr Header; @@ -614,6 +617,38 @@ static OutputSectionBase *ProgramHeaders; }; +// This class knows how to create an output section for a given +// input section. Output section type is determined by various +// factors, including input section's sh_flags, sh_type and +// linker scripts. +template struct SectionKey { + typedef typename std::conditional::type uintX_t; + StringRef Name; + uint32_t Type; + uintX_t Flags; + uintX_t Alignment; +}; + +template class OutputSectionFactory { + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::uint uintX_t; + typedef typename SectionKey Key; + +public: + std::pair *, bool> create(InputSectionBase *C, + StringRef OutsecName); + + OutputSectionBase *lookup(StringRef Name, uint32_t Type, + uintX_t Flags) { + return Map.lookup({Name, Type, Flags, 0}); + } + +private: + Key createKey(InputSectionBase *C, StringRef OutsecName); + + llvm::SmallDenseMap *> Map; +}; + template BuildIdSection *Out::BuildId; template DynamicSection *Out::Dynamic; template EhFrameHeader *Out::EhFrameHdr; @@ -643,4 +678,25 @@ } // namespace elf } // namespace lld +namespace llvm { +template struct DenseMapInfo> { + typedef typename lld::elf::SectionKey Key; + + static Key getEmptyKey() { + return Key{DenseMapInfo::getEmptyKey(), 0, 0, 0}; + } + static Key getTombstoneKey() { + return Key{DenseMapInfo::getTombstoneKey(), 0, 0, 0}; + } + static unsigned getHashValue(const Key &Val) { + return hash_combine(Val.Name, Val.Type, Val.Flags, Val.Alignment); + } + static bool isEqual(const Key &LHS, const Key &RHS) { + return DenseMapInfo::isEqual(LHS.Name, RHS.Name) && + LHS.Type == RHS.Type && LHS.Flags == RHS.Flags && + LHS.Alignment == RHS.Alignment; + } +}; +} // namespace llvm + #endif // LLD_ELF_OUTPUT_SECTIONS_H Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -934,7 +934,6 @@ } template void OutputSection::writeTo(uint8_t *Buf) { - ArrayRef Filler = Script::X->getFiller(this->Name); if (!Filler.empty()) fill(Buf, this->getSize(), Filler); if (Config->Threads) { @@ -1692,6 +1691,61 @@ } template +std::pair *, bool> +OutputSectionFactory::create(InputSectionBase *C, + StringRef OutsecName) { + SectionKey Key = createKey(C, OutsecName); + OutputSectionBase *&Sec = Map[Key]; + if (Sec) + return {Sec, false}; + + switch (C->SectionKind) { + case InputSectionBase::Regular: + Sec = new OutputSection(Key.Name, Key.Type, Key.Flags); + break; + case InputSectionBase::EHFrame: + Sec = new EHOutputSection(Key.Name, Key.Type, Key.Flags); + break; + case InputSectionBase::Merge: + Sec = new MergeOutputSection(Key.Name, Key.Type, Key.Flags, + Key.Alignment); + break; + case InputSectionBase::MipsReginfo: + Sec = new MipsReginfoOutputSection(); + break; + case InputSectionBase::MipsOptions: + Sec = new MipsOptionsOutputSection(); + break; + } + return {Sec, true}; +} + +template +SectionKey +OutputSectionFactory::createKey(InputSectionBase *C, + StringRef OutsecName) { + const Elf_Shdr *H = C->getSectionHdr(); + uintX_t Flags = H->sh_flags & ~SHF_GROUP; + + // For SHF_MERGE we create different output sections for each alignment. + // This makes each output section simple and keeps a single level mapping from + // input to output. + uintX_t Alignment = 0; + if (isa>(C)) + Alignment = std::max(H->sh_addralign, H->sh_entsize); + + // GNU as can give .eh_frame section type SHT_PROGBITS or SHT_X86_64_UNWIND + // depending on the construct. We want to canonicalize it so that + // there is only one .eh_frame in the end. + uint32_t Type = H->sh_type; + if (Type == SHT_PROGBITS && Config->EMachine == EM_X86_64 && + isa>(C)) + Type = SHT_X86_64_UNWIND; + + return SectionKey{OutsecName, Type, Flags, Alignment}; +} + +template MipsOptionsOutputSection::MipsOptionsOutputSection() : OutputSectionBase(".MIPS.options", SHT_MIPS_OPTIONS, SHF_ALLOC | SHF_MIPS_NOSTRIP) { @@ -1835,5 +1889,10 @@ template class BuildIdSha1; template class BuildIdSha1; template class BuildIdSha1; + +template class OutputSectionFactory; +template class OutputSectionFactory; +template class OutputSectionFactory; +template class OutputSectionFactory; } } Index: ELF/Writer.h =================================================================== --- ELF/Writer.h +++ ELF/Writer.h @@ -10,14 +10,29 @@ #ifndef LLD_ELF_WRITER_H #define LLD_ELF_WRITER_H +namespace llvm { +class StringRef; +} + namespace lld { namespace elf { template class SymbolTable; +template class InputSectionBase; +template class ObjectFile; template void writeResult(SymbolTable *Symtab); template void markLive(); + +template +llvm::StringRef getOutputSectionName(InputSectionBase *S); + +template bool isDiscarded(InputSectionBase *IS); + +template +void reportDiscarded(InputSectionBase *IS, + const elf::ObjectFile &File); } } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -10,6 +10,7 @@ #include "Writer.h" #include "Config.h" #include "LinkerScript.h" +#include "InputSection.h" #include "OutputSections.h" #include "SymbolTable.h" #include "Target.h" @@ -60,7 +61,11 @@ void copyLocalSymbols(); void addReservedSymbols(); + + std::vector *> + createRegularSections(OutputSectionFactory &Factory); void createSections(); + void addPredefinedSections(); bool needsGot(); @@ -81,8 +86,6 @@ void writeHeader(); void writeSections(); void writeBuildId(); - bool isDiscarded(InputSectionBase *IS) const; - StringRef getOutputSectionName(InputSectionBase *S) const; bool needsInterpSection() const { return !Symtab.getSharedFiles().empty() && !Config->DynamicLinker.empty(); } @@ -119,6 +122,30 @@ }; } // anonymous namespace +template +StringRef elf::getOutputSectionName(InputSectionBase *S) { + StringRef Name = S->getSectionName(); + for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.", + ".init_array.", ".fini_array.", ".ctors.", ".dtors.", + ".tbss.", ".gcc_except_table.", ".tdata."}) + if (Name.startswith(V)) + return V.drop_back(); + return Name; +} + +template bool elf::isDiscarded(InputSectionBase *S) { + return !S || S == &InputSection::Discarded || !S->Live; +} + +template +void elf::reportDiscarded(InputSectionBase *IS, + const elf::ObjectFile &File) { + if (!Config->PrintGcSections || !IS || IS->Live) + return; + llvm::errs() << "removing unused section from '" << IS->getSectionName() + << "' in file '" << File.getName() << "'\n"; +} + template void elf::writeResult(SymbolTable *Symtab) { typedef typename ELFT::uint uintX_t; typedef typename ELFT::Ehdr Elf_Ehdr; @@ -247,37 +274,6 @@ check(Buffer->commit()); } -namespace { -template struct SectionKey { - typedef typename std::conditional::type uintX_t; - StringRef Name; - uint32_t Type; - uintX_t Flags; - uintX_t Alignment; -}; -} -namespace llvm { -template struct DenseMapInfo> { - static SectionKey getEmptyKey() { - return SectionKey{DenseMapInfo::getEmptyKey(), 0, 0, - 0}; - } - static SectionKey getTombstoneKey() { - return SectionKey{DenseMapInfo::getTombstoneKey(), 0, - 0, 0}; - } - static unsigned getHashValue(const SectionKey &Val) { - return hash_combine(Val.Name, Val.Type, Val.Flags, Val.Alignment); - } - static bool isEqual(const SectionKey &LHS, - const SectionKey &RHS) { - return DenseMapInfo::isEqual(LHS.Name, RHS.Name) && - LHS.Type == RHS.Type && LHS.Flags == RHS.Flags && - LHS.Alignment == RHS.Alignment; - } -}; -} - // Returns the number of relocations processed. template static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body, @@ -905,10 +901,6 @@ OutputSectionBase *B) { typedef typename ELFT::uint uintX_t; - int Comp = Script::X->compareSections(A->getName(), B->getName()); - if (Comp != 0) - return Comp < 0; - uintX_t AFlags = A->getFlags(); uintX_t BFlags = B->getFlags(); @@ -1049,36 +1041,6 @@ } template -StringRef Writer::getOutputSectionName(InputSectionBase *S) const { - StringRef Dest = Script::X->getOutputSection(S); - if (!Dest.empty()) - return Dest; - - StringRef Name = S->getSectionName(); - for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.", - ".init_array.", ".fini_array.", ".ctors.", ".dtors.", - ".tbss.", ".gcc_except_table.", ".tdata."}) - if (Name.startswith(V)) - return V.drop_back(); - return Name; -} - -template -void reportDiscarded(InputSectionBase *IS, - const std::unique_ptr> &File) { - if (!Config->PrintGcSections || !IS || IS->Live) - return; - llvm::errs() << "removing unused section from '" << IS->getSectionName() - << "' in file '" << File->getName() << "'\n"; -} - -template -bool Writer::isDiscarded(InputSectionBase *S) const { - return !S || S == &InputSection::Discarded || !S->Live || - Script::X->isDiscarded(S); -} - -template static Symbol *addOptionalSynthetic(SymbolTable &Table, StringRef Name, OutputSectionBase *Sec, typename ELFT::uint Val) { @@ -1116,87 +1078,6 @@ return true; } -// This class knows how to create an output section for a given -// input section. Output section type is determined by various -// factors, including input section's sh_flags, sh_type and -// linker scripts. -namespace { -template class OutputSectionFactory { - typedef typename ELFT::Shdr Elf_Shdr; - typedef typename ELFT::uint uintX_t; - -public: - std::pair *, bool> create(InputSectionBase *C, - StringRef OutsecName); - - OutputSectionBase *lookup(StringRef Name, uint32_t Type, - uintX_t Flags) { - return Map.lookup({Name, Type, Flags, 0}); - } - -private: - SectionKey createKey(InputSectionBase *C, - StringRef OutsecName); - - SmallDenseMap, OutputSectionBase *> Map; -}; -} - -template -std::pair *, bool> -OutputSectionFactory::create(InputSectionBase *C, - StringRef OutsecName) { - SectionKey Key = createKey(C, OutsecName); - OutputSectionBase *&Sec = Map[Key]; - if (Sec) - return {Sec, false}; - - switch (C->SectionKind) { - case InputSectionBase::Regular: - Sec = new OutputSection(Key.Name, Key.Type, Key.Flags); - break; - case InputSectionBase::EHFrame: - Sec = new EHOutputSection(Key.Name, Key.Type, Key.Flags); - break; - case InputSectionBase::Merge: - Sec = new MergeOutputSection(Key.Name, Key.Type, Key.Flags, - Key.Alignment); - break; - case InputSectionBase::MipsReginfo: - Sec = new MipsReginfoOutputSection(); - break; - case InputSectionBase::MipsOptions: - Sec = new MipsOptionsOutputSection(); - break; - } - return {Sec, true}; -} - -template -SectionKey -OutputSectionFactory::createKey(InputSectionBase *C, - StringRef OutsecName) { - const Elf_Shdr *H = C->getSectionHdr(); - uintX_t Flags = H->sh_flags & ~SHF_GROUP; - - // For SHF_MERGE we create different output sections for each alignment. - // This makes each output section simple and keeps a single level mapping from - // input to output. - uintX_t Alignment = 0; - if (isa>(C)) - Alignment = std::max(H->sh_addralign, H->sh_entsize); - - // GNU as can give .eh_frame section type SHT_PROGBITS or SHT_X86_64_UNWIND - // depending on the construct. We want to canonicalize it so that - // there is only one .eh_frame in the end. - uint32_t Type = H->sh_type; - if (Type == SHT_PROGBITS && Config->EMachine == EM_X86_64 && - isa>(C)) - Type = SHT_X86_64_UNWIND; - - return SectionKey{OutsecName, Type, Flags, Alignment}; -} - // The linker is expected to define some symbols depending on // the linking result. This function defines such symbols. template void Writer::addReservedSymbols() { @@ -1275,40 +1156,42 @@ reinterpret_cast *>(S)->sortCtorsDtors(); } -// Create output section objects and add them to OutputSections. -template void Writer::createSections() { - // Add .interp first because some loaders want to see that section - // on the first page of the executable file when loaded into memory. - if (needsInterpSection()) - OutputSections.push_back(Out::Interp); - - // A core file does not usually contain unmodified segments except - // the first page of the executable. Add the build ID section now - // so that the section is included in the first page. - if (Out::BuildId) - OutputSections.push_back(Out::BuildId); +template +std::vector *> +Writer::createRegularSections(OutputSectionFactory &Factory) { + if (ScriptConfig->DoLayout) + return Script::X->createSections(Factory, Symtab); // Create output sections for input object file sections. std::vector *> RegularSections; - OutputSectionFactory Factory; for (const std::unique_ptr> &F : Symtab.getObjectFiles()) { for (InputSectionBase *C : F->getSections()) { if (isDiscarded(C)) { - reportDiscarded(C, F); + reportDiscarded(C, *F.get()); continue; } OutputSectionBase *Sec; bool IsNew; std::tie(Sec, IsNew) = Factory.create(C, getOutputSectionName(C)); - if (IsNew) { - OwningSections.emplace_back(Sec); - OutputSections.push_back(Sec); + if (IsNew) RegularSections.push_back(Sec); - } Sec->addSection(C); } } + return RegularSections; +} + +// Create output section objects and add them to OutputSections. +template void Writer::createSections() { + OutputSectionFactory Factory; + std::vector *> RegularSections = + createRegularSections(Factory); + + for (OutputSectionBase *Sec : RegularSections) { + OwningSections.emplace_back(Sec); + OutputSections.push_back(Sec); + } Out::Bss = static_cast *>( Factory.lookup(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE)); @@ -1414,8 +1297,9 @@ // This function adds linker-created Out::* sections. addPredefinedSections(); - std::stable_sort(OutputSections.begin(), OutputSections.end(), - compareSections); + if (!ScriptConfig->DoLayout) + std::stable_sort(OutputSections.begin(), OutputSections.end(), + compareSections); unsigned I = 1; for (OutputSectionBase *Sec : OutputSections) { @@ -1462,6 +1346,18 @@ OutputSections.push_back(C); }; + // Add .interp at first because some loaders want to see that section + // on the first page of the executable file when loaded into memory. + auto I = OutputSections.begin(); + if (needsInterpSection()) + I = OutputSections.insert(I, Out::Interp); + + // A core file does not usually contain unmodified segments except + // the first page of the executable. Add the build ID section now + // so that the section is included in the first page. + if (Out::BuildId) + OutputSections.insert(I, Out::BuildId); + // This order is not the same as the final output order // because we sort the sections using their attributes below. Add(Out::SymTab);