From: George Rimar Date: Sat, 4 Nov 2017 09:11:27 +0000 (+0000) Subject: [ELF] - Stop using SectionKey for creating output sections. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=343e8227b701da66cbeac867feb9ca6d5211d535;p=platform%2Fupstream%2Fllvm.git [ELF] - Stop using SectionKey for creating output sections. Stop using SectionKey for creating output sections. Initially SectionKey was designed because we merged section with use of Flags and Alignment fields. Currently LLD merges them by name only, except the case when -relocatable output is produced. In that case we still merge sections only with the same flags and alignment. There is probably no issue at all to stop using Flags and Alignment for -r and just disable the merging in that case. After doing that change we can get rid of using SectionKey. That is not only simplifies the code, but also gives some perfomance boost. I tried to link chrome and mozilla, results are next: * chrome link time goes from 1,666750355s to 1,551585364s, that is about 7%. * mozilla time changes from 3,210261947 to 3,153782940, or about 2%. Differential revision: https://reviews.llvm.org/D39594 llvm-svn: 317406 --- diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index a110d67..b4c1c80 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -142,61 +142,6 @@ void OutputSection::addSection(InputSection *IS) { } } -static SectionKey createKey(InputSectionBase *IS, StringRef OutsecName) { - // When control reaches here, mergeable sections have already been - // merged except the -r case. If that's the case, we want to combine - // mergeable sections by sh_entsize and sh_flags. - if (Config->Relocatable && (IS->Flags & SHF_MERGE)) { - uint64_t Flags = IS->Flags & (SHF_MERGE | SHF_STRINGS); - uint32_t Alignment = std::max(IS->Alignment, IS->Entsize); - return SectionKey{OutsecName, Flags, Alignment}; - } - - // The ELF spec just says - // ---------------------------------------------------------------- - // In the first phase, input sections that match in name, type and - // attribute flags should be concatenated into single sections. - // ---------------------------------------------------------------- - // - // However, it is clear that at least some flags have to be ignored for - // section merging. At the very least SHF_GROUP and SHF_COMPRESSED have to be - // ignored. We should not have two output .text sections just because one was - // in a group and another was not for example. - // - // It also seems that that wording was a late addition and didn't get the - // necessary scrutiny. - // - // Merging sections with different flags is expected by some users. One - // reason is that if one file has - // - // int *const bar __attribute__((section(".foo"))) = (int *)0; - // - // gcc with -fPIC will produce a read only .foo section. But if another - // file has - // - // int zed; - // int *const bar __attribute__((section(".foo"))) = (int *)&zed; - // - // gcc with -fPIC will produce a read write section. - // - // Last but not least, when using linker script the merge rules are forced by - // the script. Unfortunately, linker scripts are name based. This means that - // expressions like *(.foo*) can refer to multiple input sections with - // different flags. We cannot put them in different output sections or we - // would produce wrong results for - // - // start = .; *(.foo.*) end = .; *(.bar) - // - // and a mapping of .foo1 and .bar1 to one section and .foo2 and .bar2 to - // another. The problem is that there is no way to layout those output - // sections such that the .foo sections are the only thing between the start - // and end symbols. - // - // Given the above issues, we instead merge sections by name and error on - // incompatible types and flags. - return SectionKey{OutsecName, 0, 0}; -} - OutputSectionFactory::OutputSectionFactory() {} void elf::sortByOrder(MutableArrayRef In, @@ -252,8 +197,55 @@ OutputSection *OutputSectionFactory::addInputSec(InputSectionBase *IS, return Out->RelocationSection; } - SectionKey Key = createKey(IS, OutsecName); - OutputSection *&Sec = Map[Key]; + // When control reaches here, mergeable sections have already been + // merged except the -r case. If that's the case, we do not combine them + // and let final link to handle this optimization. + if (Config->Relocatable && (IS->Flags & SHF_MERGE)) + return createSection(IS, OutsecName); + + // The ELF spec just says + // ---------------------------------------------------------------- + // In the first phase, input sections that match in name, type and + // attribute flags should be concatenated into single sections. + // ---------------------------------------------------------------- + // + // However, it is clear that at least some flags have to be ignored for + // section merging. At the very least SHF_GROUP and SHF_COMPRESSED have to be + // ignored. We should not have two output .text sections just because one was + // in a group and another was not for example. + // + // It also seems that that wording was a late addition and didn't get the + // necessary scrutiny. + // + // Merging sections with different flags is expected by some users. One + // reason is that if one file has + // + // int *const bar __attribute__((section(".foo"))) = (int *)0; + // + // gcc with -fPIC will produce a read only .foo section. But if another + // file has + // + // int zed; + // int *const bar __attribute__((section(".foo"))) = (int *)&zed; + // + // gcc with -fPIC will produce a read write section. + // + // Last but not least, when using linker script the merge rules are forced by + // the script. Unfortunately, linker scripts are name based. This means that + // expressions like *(.foo*) can refer to multiple input sections with + // different flags. We cannot put them in different output sections or we + // would produce wrong results for + // + // start = .; *(.foo.*) end = .; *(.bar) + // + // and a mapping of .foo1 and .bar1 to one section and .foo2 and .bar2 to + // another. The problem is that there is no way to layout those output + // sections such that the .foo sections are the only thing between the start + // and end symbols. + // + // Given the above issues, we instead merge sections by name and error on + // incompatible types and flags. + OutputSection *&Sec = Map[OutsecName]; if (Sec) { Sec->addSection(cast(IS)); return nullptr; @@ -265,24 +257,6 @@ OutputSection *OutputSectionFactory::addInputSec(InputSectionBase *IS, OutputSectionFactory::~OutputSectionFactory() {} -SectionKey DenseMapInfo::getEmptyKey() { - return SectionKey{DenseMapInfo::getEmptyKey(), 0, 0}; -} - -SectionKey DenseMapInfo::getTombstoneKey() { - return SectionKey{DenseMapInfo::getTombstoneKey(), 0, 0}; -} - -unsigned DenseMapInfo::getHashValue(const SectionKey &Val) { - return hash_combine(Val.Name, Val.Flags, Val.Alignment); -} - -bool DenseMapInfo::isEqual(const SectionKey &LHS, - const SectionKey &RHS) { - return DenseMapInfo::isEqual(LHS.Name, RHS.Name) && - LHS.Flags == RHS.Flags && LHS.Alignment == RHS.Alignment; -} - uint64_t elf::getHeaderSize() { if (Config->OFormatBinary) return 0; diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index 078dd23..e421123 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -131,24 +131,9 @@ struct Out { static OutputSection *FiniArray; }; -struct SectionKey { - StringRef Name; - uint64_t Flags; - uint32_t Alignment; -}; } // namespace elf } // namespace lld -namespace llvm { -template <> struct DenseMapInfo { - static lld::elf::SectionKey getEmptyKey(); - static lld::elf::SectionKey getTombstoneKey(); - static unsigned getHashValue(const lld::elf::SectionKey &Val); - static bool isEqual(const lld::elf::SectionKey &LHS, - const lld::elf::SectionKey &RHS); -}; -} // namespace llvm - namespace lld { namespace elf { // This class knows how to create an output section for a given @@ -163,7 +148,7 @@ public: OutputSection *addInputSec(InputSectionBase *IS, StringRef OutsecName); private: - llvm::SmallDenseMap Map; + llvm::StringMap Map; }; uint64_t getHeaderSize();