Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -10,6 +10,7 @@ #ifndef LLD_ELF_LINKER_SCRIPT_H #define LLD_ELF_LINKER_SCRIPT_H +#include "OutputSections.h" #include "Writer.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/DenseMap.h" @@ -23,7 +24,7 @@ class SymbolBody; template class InputSectionBase; template class OutputSectionBase; -template class OutputSectionFactory; +template class OutputSectionFactoryBase; template class DefinedCommon; typedef std::function Expr; @@ -122,13 +123,29 @@ extern ScriptConfiguration *ScriptConfig; +// Output section factory used by linker script processor. +template +class OutputSectionBuilder : public OutputSectionFactoryBase { + typedef typename ELFT::uint uintX_t; + +public: + void addMultiple(StringRef OutputName, const InputSectionDescription *I); + void addSingle(StringRef OutputName, InputSectionBase *S); + std::vector *> finish(); + OutputSectionBase *lookup(StringRef Name, uint32_t Type, + uintX_t Flags) override; + +private: + ScriptConfiguration &Opt = *ScriptConfig; + llvm::SmallDenseMap *> Sections; +}; + // This is a runner of the linker script. template class LinkerScript { typedef typename ELFT::uint uintX_t; public: - std::vector *> - createSections(OutputSectionFactory &Factory); + std::vector *> createSections(); std::vector> createPhdrs(ArrayRef *> S); @@ -139,14 +156,12 @@ int compareSections(StringRef A, StringRef B); void addScriptedSymbols(); bool hasPhdrsCommands(); + OutputSectionFactoryBase *getFactory(); private: std::vector> getSectionMap(); - std::vector *> - getInputSections(const InputSectionDescription *); - // "ScriptConfig" is a bit too long, so define a short name for it. ScriptConfiguration &Opt = *ScriptConfig; @@ -159,6 +174,7 @@ void dispatchAssignment(SymbolAssignment *Cmd); uintX_t Dot; + std::unique_ptr> Builder; }; // Variable template is a C++14 feature, so we can't template Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -55,16 +55,9 @@ return C->Kind == InputSectionKind; } -template static bool isDiscarded(InputSectionBase *S) { - return !S || !S->Live; -} - template -bool LinkerScript::shouldKeep(InputSectionBase *S) { - for (StringRef Pat : Opt.KeptSections) - if (globMatch(Pat, S->getSectionName())) - return true; - return false; +static inline bool isDiscarded(InputSectionBase *S) { + return !S || !S->Live; } static bool match(ArrayRef Patterns, StringRef S) { @@ -74,24 +67,6 @@ return false; } -// Create a vector of (, ). -// For example, if a returned vector contains (".text" (".foo.*" ".bar.*")), -// input sections start with ".foo." or ".bar." should be added to -// ".text" section. -template -std::vector> -LinkerScript::getSectionMap() { - std::vector> Ret; - - for (const std::unique_ptr &Base1 : Opt.Commands) - if (auto *Cmd1 = dyn_cast(Base1.get())) - for (const std::unique_ptr &Base2 : Cmd1->Commands) - if (auto *Cmd2 = dyn_cast(Base2.get())) - Ret.emplace_back(Cmd1->Name, Cmd2); - - return Ret; -} - static bool fileMatches(const InputSectionDescription *Desc, StringRef Filename) { if (!globMatch(Desc->FilePattern, Filename)) @@ -99,10 +74,9 @@ return Desc->ExcludedFiles.empty() || !match(Desc->ExcludedFiles, Filename); } -// Returns input sections filtered by given glob patterns. template -std::vector *> -LinkerScript::getInputSections(const InputSectionDescription *I) { +void OutputSectionBuilder::addMultiple(StringRef OutputName, + const InputSectionDescription *I) { ArrayRef Patterns = I->SectionPatterns; std::vector *> Ret; for (const std::unique_ptr> &F : @@ -111,62 +85,17 @@ for (InputSectionBase *S : F->getSections()) if (!isDiscarded(S) && !S->OutSec && match(Patterns, S->getSectionName())) - Ret.push_back(S); + addSingle(OutputName, S); } - if ((llvm::find(Patterns, "COMMON") != Patterns.end())) - Ret.push_back(CommonInputSection::X); - - return Ret; + addSingle(OutputName, CommonInputSection::X); } template -std::vector *> -LinkerScript::createSections(OutputSectionFactory &Factory) { - std::vector *> Ret; - - // Add input section to output section. If there is no output section yet, - // then create it and add to output section list. - auto Add = [&](InputSectionBase *C, StringRef Name) { - OutputSectionBase *Sec; - bool IsNew; - std::tie(Sec, IsNew) = Factory.create(C, Name); - if (IsNew) - Ret.push_back(Sec); - Sec->addSection(C); - }; - - for (auto &P : getSectionMap()) { - StringRef OutputName = P.first; - const InputSectionDescription *I = P.second; - for (InputSectionBase *S : getInputSections(I)) { - if (OutputName == "/DISCARD/") { - S->Live = false; - reportDiscarded(S); - continue; - } - Add(S, OutputName); - } - } - - // Add all other input sections, which are not listed in script. - for (const std::unique_ptr> &F : - Symtab::X->getObjectFiles()) - for (InputSectionBase *S : F->getSections()) - if (!isDiscarded(S) && !S->OutSec) - Add(S, getOutputSectionName(S)); +std::vector *> OutputSectionBuilder::finish() { + auto &Sections = OutputSectionFactoryBase::OwningSections; + std::vector *> Result; - // Remove from the output all the sections which did not meet - // the optional constraints. - return filter(Ret); -} - -// Process ONLY_IF_RO and ONLY_IF_RW. -template -std::vector *> -LinkerScript::filter(std::vector *> &Sections) { - // In this loop, we remove output sections if they don't satisfy - // requested properties. for (const std::unique_ptr &Base : Opt.Commands) { auto *Cmd = dyn_cast(Base.get()); if (!Cmd || Cmd->Name == "/DISCARD/") @@ -175,13 +104,14 @@ if (Cmd->Constraint == ConstraintKind::NoConstraint) continue; - auto It = llvm::find_if(Sections, [&](OutputSectionBase *S) { - return S->getName() == Cmd->Name; - }); + auto It = llvm::find_if(Sections, + [&](std::unique_ptr> &S) { + return S->getName() == Cmd->Name; + }); if (It == Sections.end()) continue; - OutputSectionBase *Sec = *It; + OutputSectionBase *Sec = (*It).get(); bool Writable = (Sec->getFlags() & SHF_WRITE); bool RO = (Cmd->Constraint == ConstraintKind::ReadOnly); bool RW = (Cmd->Constraint == ConstraintKind::ReadWrite); @@ -189,7 +119,108 @@ if ((RO && Writable) || (RW && !Writable)) Sections.erase(It); } - return Sections; + + for (std::unique_ptr> &S : Sections) + Result.push_back(S.get()); + + return Result; +} + +template +static void checkCompatibility(OutputSectionBase *Out, + InputSectionBase *In) { + const typename ELFT::Shdr *InHdr = In->getSectionHdr(); + + if (Out->getType() != InHdr->sh_type) + error("failed to mix sections with incompatible types within `" + + Out->getName()); + + if ((Out->getFlags() & SHF_TLS) != (InHdr->sh_flags & SHF_TLS)) + error("failed to mix TLS and non-TLS sections within `" + Out->getName()); +} + +template +void OutputSectionBuilder::addSingle(StringRef OutputName, + InputSectionBase *S) { + if (OutputName == "/DISCARD/") { + S->Live = false; + reportDiscarded(S); + return; + } + + OutputSectionBase *&Sec = Sections[OutputName]; + if (!Sec) { + bool IsNew; + auto Key = OutputSectionFactoryBase::createKey(S, OutputName); + std::tie(Sec, IsNew) = OutputSectionFactoryBase::create(S, Key); + } + checkCompatibility(Sec, S); + if (HasError) + return; + + const typename ELFT::Shdr *InHdr = S->getSectionHdr(); + Sec->setFlags(Sec->getFlags() | InHdr->sh_flags); + + Sec->addSection(S); +} + +template +OutputSectionBase *OutputSectionBuilder::lookup(StringRef Name, + uint32_t Type, + uintX_t Flags) { + auto It = Sections.find(Name); + if (It == Sections.end()) + return nullptr; + + OutputSectionBase *Sec = (*It).second; + + return (Sec->getFlags() == Flags) && (Sec->getType() == Type) ? Sec : nullptr; +} + +template +bool LinkerScript::shouldKeep(InputSectionBase *S) { + for (StringRef Pat : Opt.KeptSections) + if (globMatch(Pat, S->getSectionName())) + return true; + return false; +} + +// Create a vector of (, ). +// For example, if a returned vector contains (".text" (".foo.*" ".bar.*")), +// input sections start with ".foo." or ".bar." should be added to +// ".text" section. +template +std::vector> +LinkerScript::getSectionMap() { + std::vector> Ret; + + for (const std::unique_ptr &Base1 : Opt.Commands) + if (auto *Cmd1 = dyn_cast(Base1.get())) + for (const std::unique_ptr &Base2 : Cmd1->Commands) + if (auto *Cmd2 = dyn_cast(Base2.get())) + Ret.emplace_back(Cmd1->Name, Cmd2); + + return Ret; +} + +template +std::vector *> LinkerScript::createSections() { + std::vector *> Ret; + + Builder = llvm::make_unique>(); + for (auto &P : getSectionMap()) + Builder->addMultiple(P.first, P.second); + + // Add all other input sections, which are not listed in script. + for (const std::unique_ptr> &F : + Symtab::X->getObjectFiles()) + for (InputSectionBase *S : F->getSections()) + if (!isDiscarded(S) && !S->OutSec) + Builder->addSingle(getOutputSectionName(S), S); + + // Remove from the output all the sections which did not meet + // the optional constraints. + return Builder->finish(); } template @@ -385,6 +416,11 @@ return !Opt.PhdrsCommands.empty(); } +template +OutputSectionFactoryBase *LinkerScript::getFactory() { + return Builder.get(); +} + // Returns indices of ELF headers containing specific section, identified // by Name. Each index is a zero based number of ELF header listed within // PHDRS {} script block. Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -65,6 +65,7 @@ uintX_t getSize() const { return Header.sh_size; } void setSize(uintX_t Val) { Header.sh_size = Val; } uintX_t getFlags() const { return Header.sh_flags; } + void setFlags(uintX_t Flags) { Header.sh_flags = Flags; } uint32_t getPhdrFlags() const; uintX_t getFileOff() const { return Header.sh_offset; } uintX_t getAlignment() const { return Header.sh_addralign; } @@ -671,8 +672,29 @@ // input section. Output section type is determined by various // factors, including input section's sh_flags, sh_type and // linker scripts. -template class OutputSectionFactory { +template class OutputSectionFactoryBase { + typedef typename ELFT::uint uintX_t; typedef typename ELFT::Shdr Elf_Shdr; + typedef typename elf::SectionKey Key; + +public: + virtual ~OutputSectionFactoryBase() = default; + + virtual OutputSectionBase *lookup(StringRef Name, uint32_t Type, + uintX_t Flags) { + return nullptr; + } + +protected: + Key createKey(InputSectionBase *C, StringRef OutsecName); + std::pair *, bool> create(InputSectionBase *C, + const Key &Key); + + std::vector>> OwningSections; +}; + +template +class OutputSectionFactory : public OutputSectionFactoryBase { typedef typename ELFT::uint uintX_t; typedef typename elf::SectionKey Key; @@ -683,10 +705,7 @@ OutputSectionBase *lookup(StringRef Name, uint32_t Type, uintX_t Flags); private: - Key createKey(InputSectionBase *C, StringRef OutsecName); - llvm::SmallDenseMap *> Map; - std::vector>> OwningSections; }; template BuildIdSection *Out::BuildId; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -1737,14 +1737,28 @@ } template -std::pair *, bool> -OutputSectionFactory::create(InputSectionBase *C, - StringRef OutsecName) { - SectionKey Key = createKey(C, OutsecName); - OutputSectionBase *&Sec = Map[Key]; - if (Sec) - return {Sec, false}; +SectionKey +OutputSectionFactoryBase::createKey(InputSectionBase *C, + StringRef OutsecName) { + const Elf_Shdr *H = C->getSectionHdr(); + uintX_t Flags = H->sh_flags & ~SHF_GROUP & ~SHF_COMPRESSED; + + // 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); + + uint32_t Type = H->sh_type; + return SectionKey{OutsecName, Type, Flags, Alignment}; +} +template +std::pair *, bool> +OutputSectionFactoryBase::create(InputSectionBase *C, + const Key &Key) { + OutputSectionBase *Sec; switch (C->SectionKind) { case InputSectionBase::Regular: Sec = new OutputSection(Key.Name, Key.Type, Key.Flags); @@ -1767,30 +1781,27 @@ } template +std::pair *, bool> +OutputSectionFactory::create(InputSectionBase *C, + StringRef OutsecName) { + SectionKey Key = + OutputSectionFactoryBase::createKey(C, OutsecName); + OutputSectionBase *&Sec = Map[Key]; + if (Sec) + return {Sec, false}; + + bool IsNew; + std::tie(Sec, IsNew) = OutputSectionFactoryBase::create(C, Key); + return std::make_pair(Sec, IsNew); +} + +template OutputSectionBase *OutputSectionFactory::lookup(StringRef Name, uint32_t Type, uintX_t Flags) { return Map.lookup({Name, Type, Flags, 0}); } -template -SectionKey -OutputSectionFactory::createKey(InputSectionBase *C, - StringRef OutsecName) { - const Elf_Shdr *H = C->getSectionHdr(); - uintX_t Flags = H->sh_flags & ~SHF_GROUP & ~SHF_COMPRESSED; - - // 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); - - uint32_t Type = H->sh_type; - return SectionKey{OutsecName, Type, Flags, Alignment}; -} - template typename lld::elf::SectionKey DenseMapInfo>::getEmptyKey() { Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -233,9 +233,8 @@ CommonInputSection Common(getCommonSymbols()); CommonInputSection::X = &Common; - OutputSections = ScriptConfig->HasContents - ? Script::X->createSections(Factory) - : createSections(); + OutputSections = ScriptConfig->HasContents ? Script::X->createSections() + : createSections(); finalizeSections(); if (HasError) return; @@ -661,24 +660,26 @@ template void Writer::finalizeSections() { // Create output sections for input object file sections. std::vector *> RegularSections = OutputSections; + OutputSectionFactoryBase *Fac = + ScriptConfig->HasContents ? Script::X->getFactory() : &Factory; // If we have a .opd section (used under PPC64 for function descriptors), // store a pointer to it here so that we can use it later when processing // relocations. - Out::Opd = Factory.lookup(".opd", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC); + Out::Opd = Fac->lookup(".opd", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC); - Out::Dynamic->PreInitArraySec = Factory.lookup( - ".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC); + Out::Dynamic->PreInitArraySec = + Fac->lookup(".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC); Out::Dynamic->InitArraySec = - Factory.lookup(".init_array", SHT_INIT_ARRAY, SHF_WRITE | SHF_ALLOC); + Fac->lookup(".init_array", SHT_INIT_ARRAY, SHF_WRITE | SHF_ALLOC); Out::Dynamic->FiniArraySec = - Factory.lookup(".fini_array", SHT_FINI_ARRAY, SHF_WRITE | SHF_ALLOC); + Fac->lookup(".fini_array", SHT_FINI_ARRAY, SHF_WRITE | SHF_ALLOC); // Sort section contents for __attribute__((init_priority(N)). sortInitFini(Out::Dynamic->InitArraySec); sortInitFini(Out::Dynamic->FiniArraySec); - sortCtorsDtors(Factory.lookup(".ctors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC)); - sortCtorsDtors(Factory.lookup(".dtors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC)); + sortCtorsDtors(Fac->lookup(".ctors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC)); + sortCtorsDtors(Fac->lookup(".dtors", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC)); // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop // symbols for sections, so that the runtime can get the start and end Index: test/ELF/linkerscript/linkerscript-repsection-va.s =================================================================== --- test/ELF/linkerscript/linkerscript-repsection-va.s +++ test/ELF/linkerscript/linkerscript-repsection-va.s @@ -7,9 +7,8 @@ # CHECK: Sections: # CHECK-NEXT: Idx Name Size Address Type # CHECK-NEXT: 0 00000000 0000000000000000 -# CHECK-NEXT: 1 .foo 00000004 0000000000000158 DATA -# CHECK-NEXT: 2 .foo 00000004 000000000000015c DATA -# CHECK-NEXT: 3 .text 00000001 0000000000000160 TEXT DATA +# CHECK-NEXT: 1 .foo 00000008 0000000000000158 DATA +# CHECK-NEXT: 2 .text 00000001 0000000000000160 TEXT DATA .global _start _start: