Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -13,6 +13,7 @@ #include "ICF.h" #include "InputFiles.h" #include "InputSection.h" +#include "OutputSections.h" #include "LinkerScript.h" #include "Strings.h" #include "SymbolListFile.h" Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -23,7 +23,6 @@ class SymbolBody; template class InputSectionBase; template class OutputSectionBase; -template class OutputSectionFactory; template class DefinedCommon; typedef std::function Expr; @@ -138,7 +137,7 @@ typedef typename ELFT::uint uintX_t; public: - void createSections(OutputSectionFactory &Factory); + void createSections(); std::vector> createPhdrs(); @@ -169,6 +168,8 @@ size_t getPhdrIndex(StringRef PhdrName); uintX_t Dot; + + std::vector>> OwningSections; }; // Variable template is a C++14 feature, so we can't template Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -121,18 +121,67 @@ return Ret; } -// Add input section to output section. If there is no output section yet, -// then create it and add to output section list. -template -static void addSection(OutputSectionFactory &Factory, - std::vector *> &Out, - InputSectionBase *C, StringRef Name) { - OutputSectionBase *Sec; - bool IsNew; - std::tie(Sec, IsNew) = Factory.create(C, Name); - if (IsNew) - Out.push_back(Sec); - Sec->addSection(C); +namespace { +template class OutputSectionFactory { + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::uint uintX_t; + typedef std::vector>> Map; + +private: + static OutputSectionBase *allocSection(unsigned Kind, StringRef Name, + uintX_t Flags, uintX_t Alignment, + uint32_t Type) { + switch (Kind) { + case InputSectionBase::Regular: + return new OutputSection(Name, Type, Flags); + case InputSectionBase::Merge: + return new MergeOutputSection(Name, Type, Flags, Alignment); + case InputSectionBase::MipsReginfo: + return new MipsReginfoOutputSection(); + case InputSectionBase::MipsOptions: + return new MipsOptionsOutputSection(); + default: + llvm_unreachable("unknown section kind"); + } + } + +public: + static void create(Map &OwningSections, InputSectionBase *C, + StringRef OutsecName) { + if (C->SectionKind == InputSectionBase::EHFrame) { + Out::EhFrame->addSection(C); + return; + } + + OutputSectionBase *Sec = nullptr; + for (std::unique_ptr> &S : OwningSections) + if (S->getName() == OutsecName) { + Sec = S.get(); + break; + } + + const Elf_Shdr *H = C->getSectionHdr(); + uintX_t Flags = H->sh_flags & ~SHF_GROUP & ~SHF_COMPRESSED; + uintX_t Alignment = 0; + if (isa>(C)) + Alignment = std::max(H->sh_addralign, H->sh_entsize); + uint32_t Type = H->sh_type; + + if (!Sec) { + Sec = allocSection(C->SectionKind, OutsecName, Flags, Alignment, Type); + OwningSections.emplace_back(Sec); + } else { + if ((Sec->getFlags() & SHF_MERGE) != (Flags & SHF_MERGE)) + fatal("combine of mergeable and non-mergeable sections is not " + "supported yet"); + + Sec->updateAlignment(Alignment); + Sec->combineFlags(Flags); + } + + Sec->addSection(C); + } +}; } template @@ -157,9 +206,7 @@ return compareAlignment; } -template -void LinkerScript::createSections( - OutputSectionFactory &Factory) { +template void LinkerScript::createSections() { for (auto &P : getSectionMap()) { StringRef OutputName = P.first; const InputSectionDescription *Cmd = P.second; @@ -181,7 +228,7 @@ getComparator(Cmd->SortOuter)); for (InputSectionBase *S : Sections) - addSection(Factory, *OutputSections, S, OutputName); + OutputSectionFactory::create(OwningSections, S, OutputName); } // Add all other input sections, which are not listed in script. @@ -189,7 +236,11 @@ Symtab::X->getObjectFiles()) for (InputSectionBase *S : F->getSections()) if (!isDiscarded(S) && !S->OutSec) - addSection(Factory, *OutputSections, S, getOutputSectionName(S)); + OutputSectionFactory::create(OwningSections, S, + getOutputSectionName(S)); + + for (std::unique_ptr>& Sec : OwningSections) + OutputSections->push_back(Sec.get()); // Remove from the output all the sections which did not meet // the optional constraints. @@ -257,36 +308,35 @@ continue; } - // Find all the sections with required name. There can be more than - // one section with such name, if the alignment, flags or type - // attribute differs. auto *Cmd = cast(Base.get()); - for (OutputSectionBase *Sec : Sections) { - if (Sec->getName() != Cmd->Name) - continue; - - if (Cmd->AddrExpr) - Dot = Cmd->AddrExpr(Dot); - - if (Cmd->AlignExpr) - Sec->updateAlignment(Cmd->AlignExpr(Dot)); - - if ((Sec->getFlags() & SHF_TLS) && Sec->getType() == SHT_NOBITS) { - uintX_t TVA = Dot + ThreadBssOffset; - TVA = alignTo(TVA, Sec->getAlignment()); - Sec->setVA(TVA); - ThreadBssOffset = TVA - Dot + Sec->getSize(); - continue; - } + auto I = llvm::find_if(Sections, [&](OutputSectionBase *S) { + return S->getName() == Cmd->Name; + }); + if (I == Sections.end()) + continue; - if (Sec->getFlags() & SHF_ALLOC) { - Dot = alignTo(Dot, Sec->getAlignment()); - Sec->setVA(Dot); - MinVA = std::min(MinVA, Dot); - Dot += Sec->getSize(); - continue; - } + OutputSectionBase *Sec = *I; + if (Cmd->AddrExpr) + Dot = Cmd->AddrExpr(Dot); + + if (Cmd->AlignExpr) + Sec->updateAlignment(Cmd->AlignExpr(Dot)); + + if ((Sec->getFlags() & SHF_TLS) && Sec->getType() == SHT_NOBITS) { + uintX_t TVA = Dot + ThreadBssOffset; + TVA = alignTo(TVA, Sec->getAlignment()); + Sec->setVA(TVA); + ThreadBssOffset = TVA - Dot + Sec->getSize(); + continue; } + + if (!(Sec->getFlags() & SHF_ALLOC)) + continue; + + Dot = alignTo(Dot, Sec->getAlignment()); + Sec->setVA(Dot); + MinVA = std::min(MinVA, Dot); + Dot += Sec->getSize(); } // ELF and Program headers need to be right before the first section in Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -70,6 +70,8 @@ uintX_t getAlignment() const { return Header.sh_addralign; } uint32_t getType() const { return Header.sh_type; } + void combineFlags(uintX_t Flag) { Header.sh_flags |= Flag; } + void updateAlignment(uintX_t Alignment) { if (Alignment > Header.sh_addralign) Header.sh_addralign = Alignment; @@ -657,34 +659,6 @@ static OutputSectionBase *FiniArray; }; -template struct SectionKey { - typedef typename std::conditional::type uintX_t; - StringRef Name; - uint32_t Type; - uintX_t Flags; - uintX_t Alignment; -}; - -// 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 class OutputSectionFactory { - typedef typename ELFT::Shdr Elf_Shdr; - typedef typename ELFT::uint uintX_t; - typedef typename elf::SectionKey Key; - -public: - std::pair *, bool> create(InputSectionBase *C, - StringRef OutsecName); - -private: - Key createKey(InputSectionBase *C, StringRef OutsecName); - - llvm::SmallDenseMap *> Map; - std::vector>> OwningSections; -}; - template BuildIdSection *Out::BuildId; template DynamicSection *Out::Dynamic; template EhFrameHeader *Out::EhFrameHdr; @@ -719,15 +693,4 @@ } // namespace elf } // namespace lld -namespace llvm { -template struct DenseMapInfo> { - typedef typename lld::elf::SectionKey Key; - - static Key getEmptyKey(); - static Key getTombstoneKey(); - static unsigned getHashValue(const Key &Val); - static bool isEqual(const Key &LHS, const Key &RHS); -}; -} - #endif Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -1737,86 +1737,6 @@ S->OutSec = this; } -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: - return {Out::EhFrame, false}; - 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; - } - OwningSections.emplace_back(Sec); - 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 & ~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() { - return SectionKey{DenseMapInfo::getEmptyKey(), 0, 0, 0}; -} - -template -typename lld::elf::SectionKey -DenseMapInfo>::getTombstoneKey() { - return SectionKey{DenseMapInfo::getTombstoneKey(), 0, 0, - 0}; -} - -template -unsigned -DenseMapInfo>::getHashValue(const Key &Val) { - return hash_combine(Val.Name, Val.Type, Val.Flags, Val.Alignment); -} - -template -bool DenseMapInfo>::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 { -template struct DenseMapInfo>; -template struct DenseMapInfo>; -} - namespace lld { namespace elf { template class OutputSectionBase; @@ -1944,9 +1864,5 @@ template class BuildIdHexstring; template class BuildIdHexstring; -template class OutputSectionFactory; -template class OutputSectionFactory; -template class OutputSectionFactory; -template class OutputSectionFactory; } } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -30,6 +30,96 @@ using namespace lld::elf; 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; + } +}; +} + +namespace { +// 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 class OutputSectionFactory { + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::uint uintX_t; + typedef typename SectionKey SectionKey; + +public: + std::pair *, bool> 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: + return {Out::EhFrame, false}; + 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; + } + OwningSections.emplace_back(Sec); + return {Sec, true}; + } + +private: + SectionKey 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 {OutsecName, Type, Flags, Alignment}; + } + + llvm::SmallDenseMap *> Map; + std::vector>> OwningSections; +}; + // The writer writes a SymbolTable result to a file. template class Writer { public: @@ -243,7 +333,7 @@ Script::X->OutputSections = &OutputSections; if (ScriptConfig->HasContents) - Script::X->createSections(Factory); + Script::X->createSections(); else createSections(); Index: test/ELF/linkerscript/linkerscript-merge-sections.s =================================================================== --- test/ELF/linkerscript/linkerscript-merge-sections.s +++ test/ELF/linkerscript/linkerscript-merge-sections.s @@ -0,0 +1,39 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "SECTIONS { .aaa : { *(.aaa.*) } }" > %t.script +# RUN: ld.lld -o %t1.out --script %t.script %t +# RUN: llvm-objdump -section-headers %t1.out | FileCheck %s + +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .aaa 00000038 0000000000000160 TEXT DATA +# CHECK-NEXT: 2 .text 00000001 0000000000000198 TEXT DATA +# CHECK-NEXT: 3 .symtab 00000030 0000000000000000 +# CHECK-NEXT: 4 .shstrtab 00000026 0000000000000000 +# CHECK-NEXT: 5 .strtab 00000008 0000000000000000 + +.global _start +_start: + nop + +.section .aaa.3, "a" +.align 1 +.quad 1 + + +.section .aaa.4, "awS" +.align 2 +.quad 2 + +.section .aaa.1, "aS" +.align 4 +.quad 3 + +.section .aaa.2, "ax" +.align 8 +.quad 4 + +.section .aaa.2, "ax" +.align 16 +.quad 5 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: