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(); @@ -166,6 +165,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 @@ -137,6 +137,62 @@ } namespace { +template class OutputSectionFactory { + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::uint uintX_t; + typedef std::vector>> Map; + +private: + Map &OutputSections; + + 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); + default: + llvm_unreachable("unknown section kind"); + } + } + +public: + OutputSectionFactory(Map &OutputSections) : OutputSections(OutputSections) {} + + std::pair *, bool> create(InputSectionBase *C, + StringRef OutsecName) { + bool IsNew = true; + OutputSectionBase *Sec = nullptr; + for (std::unique_ptr> &S : OutputSections) + if (S->getName() == OutsecName) { + Sec = S.get(); + IsNew = false; + 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); + OutputSections.emplace_back(Sec); + return {Sec, IsNew}; + } + + 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); + return {Sec, IsNew}; + } +}; + template class LayoutInputSection : public InputSection { public: LayoutInputSection(SymbolAssignment *Cmd); @@ -255,9 +311,8 @@ return compareAlignment; } -template -void LinkerScript::createSections( - OutputSectionFactory &Factory) { +template void LinkerScript::createSections() { + OutputSectionFactory Factory(OwningSections); OutputSectionBuilder Builder(Factory, OutputSections); auto Add = [&](StringRef OutputName, const InputSectionDescription *Cmd) { @@ -355,7 +410,7 @@ I->OutSecOff = Off; Off += I->getSize(); } - // Update section size inside for-loop, so that SIZEOF + // Update section size inside for-loop, so that SIZEOF // works correctly in the case below: // .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) } Sec->setSize(Off); Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -97,6 +97,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; @@ -754,34 +756,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; @@ -816,15 +790,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,88 +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; - case InputSectionBase::Layout: - llvm_unreachable("Invalid section type"); - } - 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; @@ -1945,10 +1863,5 @@ template class BuildIdHexstring; 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,98 @@ 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; + case InputSectionBase::Layout: + llvm_unreachable("Invalid section type"); + } + 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: @@ -246,7 +338,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: