Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -27,6 +27,7 @@ struct SectionPiece; template class DefinedRegular; +template class MergeSection; template class ObjectFile; template class OutputSection; class OutputSectionBase; @@ -200,6 +201,11 @@ SectionPiece *getSectionPiece(uintX_t Offset); const SectionPiece *getSectionPiece(uintX_t Offset) const; + // Mergeable input sections with different attributes are placed to + // synthetic sections which are parts of regular output section. + // That way we can emit a single output section at the end. + MergeSection *MergeSec = nullptr; + private: void splitStrings(ArrayRef A, size_t Size); void splitNonStrings(ArrayRef A, size_t Size); Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -84,7 +84,8 @@ // If it is not a mergeable section, overwrite the flag so that the flag // is consistent with the class. This inconsistency could occur when // string merging is disabled using -O0 flag. - if (!Config->Relocatable && !isa>(this)) + if (!Config->Relocatable && !isa>(this) && + !isa>(this)) this->Flags &= ~(SHF_MERGE | SHF_STRINGS); } @@ -130,8 +131,10 @@ // .eh_frame that is known to be the first in the link. It does that to // identify the start of the output .eh_frame. return Offset; - case Merge: - return cast>(this)->getOffset(Offset); + case Merge: { + const MergeInputSection *MS = cast>(this); + return MS->MergeSec ? MS->MergeSec->OutSecOff + MS->getOffset(Offset) : 0; + } } llvm_unreachable("invalid section kind"); } Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -26,6 +26,7 @@ template class InputSection; template class InputSectionBase; template class MergeInputSection; +template class MergeSection; template class OutputSection; template class ObjectFile; template class SharedFile; @@ -67,6 +68,19 @@ Addralign = Alignment; } + // Some sections hold a table of fixed-size entries, though we + // can merge sections with different sh_entsize. In this way we set + // sh_entsize to 0 in the output because in this case section does + // not hold a table of fixed-size entries. + void updateEntsize(uint64_t Size) { + if (!Size || Entsize == (uint64_t)-1) + return; + if (Entsize && Entsize != Size) + Entsize = (uint64_t)-1; + else + Entsize = Size; + } + // If true, this section will be page aligned on disk. // Typically the first section of each PT_LOAD segment has this flag. bool PageAlign = false; @@ -124,30 +138,9 @@ // Location in the output buffer. uint8_t *Loc = nullptr; -}; - -template -class MergeOutputSection final : public OutputSectionBase { - typedef typename ELFT::uint uintX_t; - -public: - MergeOutputSection(StringRef Name, uint32_t Type, uintX_t Flags, - uintX_t Alignment); - void addSection(InputSectionData *S) override; - void writeTo(uint8_t *Buf) override; - void finalize() override; - bool shouldTailMerge() const; - Kind getKind() const override { return Merge; } - static bool classof(const OutputSectionBase *B) { - return B->getKind() == Merge; - } private: - void finalizeTailMerge(); - void finalizeNoTailMerge(); - - llvm::StringTableBuilder Builder; - std::vector *> Sections; + std::vector *> MergeSections; }; struct CieRecord { Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -115,6 +115,12 @@ this->Link = D->OutSec->SectionIndex; } + // This can happen if we join several mergeable sections with different + // sh_entsize. In this case output section does not hold a table of + // fixed-size enties and we set sh_entsize to zero. + if (this->Entsize == (uint64_t)-1) + this->Entsize = 0; + uint32_t Type = this->Type; if (!Config->Relocatable || (Type != SHT_RELA && Type != SHT_REL)) return; @@ -129,6 +135,31 @@ template void OutputSection::addSection(InputSectionData *C) { assert(C->Live); + + // If we add mergable input section we might want to create or + // use existing synthetic MergeSection for each input section group. + // Sections are grouped by attributes. + if (isa>(C)) { + auto *MS = cast>(C); + uintX_t Flags = getOutFlags(MS); + uintX_t Alignment = std::max(MS->Alignment, MS->Entsize); + + auto I = llvm::find_if(MergeSections, [=](MergeSection *MS) { + return MS->Flags == Flags && MS->Alignment == Alignment; + }); + if (I == MergeSections.end()) { + MergeSection *Syn = + make>(MS->Name, MS->Type, Flags, Alignment); + Sections.push_back(Syn); + MergeSections.push_back(Syn); + I = std::prev(MergeSections.end()); + } + (*I)->addSection(MS, this); + this->updateAlignment(Alignment); + this->updateEntsize(MS->Entsize); + return; + } + auto *S = cast>(C); Sections.push_back(S); S->OutSec = this; @@ -465,71 +496,6 @@ } template -MergeOutputSection::MergeOutputSection(StringRef Name, uint32_t Type, - uintX_t Flags, uintX_t Alignment) - : OutputSectionBase(Name, Type, Flags), - Builder(StringTableBuilder::RAW, Alignment) {} - -template void MergeOutputSection::writeTo(uint8_t *Buf) { - Builder.write(Buf); -} - -template -void MergeOutputSection::addSection(InputSectionData *C) { - auto *Sec = cast>(C); - Sec->OutSec = this; - this->updateAlignment(Sec->Alignment); - this->Entsize = Sec->Entsize; - Sections.push_back(Sec); -} - -template bool MergeOutputSection::shouldTailMerge() const { - return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2; -} - -template void MergeOutputSection::finalizeTailMerge() { - // Add all string pieces to the string table builder to create section - // contents. - for (MergeInputSection *Sec : Sections) - for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) - if (Sec->Pieces[I].Live) - Builder.add(Sec->getData(I)); - - // Fix the string table content. After this, the contents will never change. - Builder.finalize(); - this->Size = Builder.getSize(); - - // finalize() fixed tail-optimized strings, so we can now get - // offsets of strings. Get an offset for each string and save it - // to a corresponding StringPiece for easy access. - for (MergeInputSection *Sec : Sections) - for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) - if (Sec->Pieces[I].Live) - Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I)); -} - -template void MergeOutputSection::finalizeNoTailMerge() { - // Add all string pieces to the string table builder to create section - // contents. Because we are not tail-optimizing, offsets of strings are - // fixed when they are added to the builder (string table builder contains - // a hash table from strings to offsets). - for (MergeInputSection *Sec : Sections) - for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) - if (Sec->Pieces[I].Live) - Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I)); - - Builder.finalizeInOrder(); - this->Size = Builder.getSize(); -} - -template void MergeOutputSection::finalize() { - if (shouldTailMerge()) - finalizeTailMerge(); - else - finalizeNoTailMerge(); -} - -template static typename ELFT::uint getOutFlags(InputSectionBase *S) { return S->Flags & ~SHF_GROUP & ~SHF_COMPRESSED; } @@ -540,16 +506,14 @@ typedef typename ELFT::uint uintX_t; uintX_t Flags = getOutFlags(C); - // 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. // In case of relocatable object generation we do not try to perform merging // and treat SHF_MERGE sections as regular ones, but also create different // output sections for them to allow merging at final linking stage. uintX_t Alignment = 0; - if (isa>(C) || - (Config->Relocatable && (C->Flags & SHF_MERGE))) + if (Config->Relocatable && (C->Flags & SHF_MERGE)) Alignment = std::max(C->Alignment, C->Entsize); + else + Flags &= ~(SHF_MERGE | SHF_STRINGS); return SectionKey{OutsecName, C->Type, Flags, Alignment}; } @@ -573,18 +537,11 @@ return {Sec, false}; } - uint32_t Type = C->Type; - switch (C->kind()) { - case InputSectionBase::Regular: - case InputSectionBase::Synthetic: - Sec = make>(Key.Name, Type, Flags); - break; - case InputSectionBase::EHFrame: + if (C->kind() == InputSectionBase::EHFrame) return {Out::EhFrame, false}; - case InputSectionBase::Merge: - Sec = make>(Key.Name, Type, Flags, Key.Alignment); - break; - } + + uint32_t Type = C->Type; + Sec = make>(Key.Name, Type, Flags); return {Sec, true}; } @@ -638,11 +595,6 @@ template class EhOutputSection; template class EhOutputSection; -template class MergeOutputSection; -template class MergeOutputSection; -template class MergeOutputSection; -template class MergeOutputSection; - template class OutputSectionFactory; template class OutputSectionFactory; template class OutputSectionFactory; Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -13,6 +13,7 @@ #include "GdbIndex.h" #include "InputSection.h" #include "llvm/ADT/MapVector.h" +#include "llvm/MC/StringTableBuilder.h" namespace lld { namespace elf { @@ -557,6 +558,30 @@ bool empty() const override; }; +// MergeSection is a class that allows us to put mergeable sections +// with different attributes in a single output sections. To do that +// we put them into MergeSection synthetic input sections which are +// attached to regular output sections. +template class MergeSection final : public SyntheticSection { + typedef typename ELFT::uint uintX_t; + +public: + MergeSection(StringRef Name, uint32_t Type, uintX_t Flags, uintX_t Alignment); + void addSection(MergeInputSection *MS, OutputSection *OutSec); + void writeTo(uint8_t *Buf) override; + void finalize() override; + bool shouldTailMerge() const; + size_t getSize() const override; + +private: + void finalizeTailMerge(); + void finalizeNoTailMerge(); + + bool Finalized = false; + llvm::StringTableBuilder Builder; + std::vector *> Sections; +}; + // .MIPS.abiflags section. template class MipsAbiFlagsSection final : public SyntheticSection { Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -1669,6 +1669,78 @@ } template +MergeSection::MergeSection(StringRef Name, uint32_t Type, uintX_t Flags, + uintX_t Alignment) + : SyntheticSection(Flags, Type, Alignment, Name), + Builder(StringTableBuilder::RAW, Alignment) {} + +template +void MergeSection::addSection(MergeInputSection *MS, + OutputSection *OutSec) { + assert(!Finalized); + MS->OutSec = OutSec; + MS->MergeSec = this; + Sections.push_back(MS); +} + +template void MergeSection::writeTo(uint8_t *Buf) { + Builder.write(Buf); +} + +template void MergeSection::finalize() { + if (Finalized) + return; + if (shouldTailMerge()) + finalizeTailMerge(); + else + finalizeNoTailMerge(); + Finalized = true; +} + +template bool MergeSection::shouldTailMerge() const { + return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2; +} + +template void MergeSection::finalizeTailMerge() { + // Add all string pieces to the string table builder to create section + // contents. + for (MergeInputSection *Sec : Sections) + for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) + if (Sec->Pieces[I].Live) + Builder.add(Sec->getData(I)); + + // Fix the string table content. After this, the contents will never change. + Builder.finalize(); + + // finalize() fixed tail-optimized strings, so we can now get + // offsets of strings. Get an offset for each string and save it + // to a corresponding StringPiece for easy access. + for (MergeInputSection *Sec : Sections) + for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) + if (Sec->Pieces[I].Live) + Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I)); +} + +template void MergeSection::finalizeNoTailMerge() { + // Add all string pieces to the string table builder to create section + // contents. Because we are not tail-optimizing, offsets of strings are + // fixed when they are added to the builder (string table builder contains + // a hash table from strings to offsets). + for (MergeInputSection *Sec : Sections) + for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) + if (Sec->Pieces[I].Live) + Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I)); + + Builder.finalizeInOrder(); +} + +template size_t MergeSection::getSize() const { + // We should finalize string builder to know the size. + const_cast *>(this)->finalize(); + return Builder.getSize(); +} + +template MipsRldMapSection::MipsRldMapSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, sizeof(typename ELFT::uint), ".rld_map") {} @@ -1810,6 +1882,11 @@ template class elf::VersionDefinitionSection; template class elf::VersionDefinitionSection; +template class elf::MergeSection; +template class elf::MergeSection; +template class elf::MergeSection; +template class elf::MergeSection; + template class elf::MipsRldMapSection; template class elf::MipsRldMapSection; template class elf::MipsRldMapSection; Index: test/ELF/merge-string-align.s =================================================================== --- test/ELF/merge-string-align.s +++ test/ELF/merge-string-align.s @@ -24,33 +24,18 @@ // CHECK-NEXT: ] // CHECK-NEXT: Address: // CHECK-NEXT: Offset: -// CHECK-NEXT: Size: 20 +// CHECK-NEXT: Size: 24 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 16 // CHECK-NEXT: EntrySize: // CHECK-NEXT: SectionData ( // CHECK-NEXT: 0000: 666F6F00 00000000 00000000 00000000 |foo.............| -// CHECK-NEXT: 0010: 62617200 |bar.| +// CHECK-NEXT: 0010: 62617200 666F6F00 |bar.foo.| // CHECK-NEXT: ) .section .rodata.str1.1,"aMS",@progbits,1 .asciz "foo" -// CHECK: Name: .rodata -// CHECK-NEXT: Type: SHT_PROGBITS -// CHECK-NEXT: Flags [ -// CHECK-NEXT: SHF_ALLOC -// CHECK-NEXT: SHF_MERGE -// CHECK-NEXT: SHF_STRINGS -// CHECK-NEXT: ] -// CHECK-NEXT: Address: -// CHECK-NEXT: Offset: -// CHECK-NEXT: Size: 4 -// CHECK-NEXT: Link: 0 -// CHECK-NEXT: Info: 0 -// CHECK-NEXT: AddressAlignment: 1 -// CHECK-NEXT: EntrySize: -// CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 666F6F00 |foo.| -// CHECK-NEXT: ) +// CHECK-NOT: Name: .rodata + Index: test/ELF/merge-string.s =================================================================== --- test/ELF/merge-string.s +++ test/ELF/merge-string.s @@ -30,13 +30,13 @@ // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x1C8 // CHECK-NEXT: Offset: 0x1C8 -// CHECK-NEXT: Size: 4 +// CHECK-NEXT: Size: 8 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 -// CHECK-NEXT: AddressAlignment: 1 -// CHECK-NEXT: EntrySize: 1 +// CHECK-NEXT: AddressAlignment: 2 +// CHECK-NEXT: EntrySize: 0 // CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 61626300 |abc.| +// CHECK-NEXT: 0000: 61626300 14000000 |abc.....| // CHECK-NEXT: ) // NOTAIL: Name: .rodata @@ -48,13 +48,13 @@ // NOTAIL-NEXT: ] // NOTAIL-NEXT: Address: 0x1C8 // NOTAIL-NEXT: Offset: 0x1C8 -// NOTAIL-NEXT: Size: 7 +// NOTAIL-NEXT: Size: 12 // NOTAIL-NEXT: Link: 0 // NOTAIL-NEXT: Info: 0 -// NOTAIL-NEXT: AddressAlignment: 1 -// NOTAIL-NEXT: EntrySize: 1 +// NOTAIL-NEXT: AddressAlignment: 2 +// NOTAIL-NEXT: EntrySize: 0 // NOTAIL-NEXT: SectionData ( -// NOTAIL-NEXT: 0000: 61626300 626300 |abc.bc.| +// NOTAIL-NEXT: 0000: 61626300 62630000 14000000 |abc.bc......| // NOTAIL-NEXT: ) // NOMERGE: Name: .rodata @@ -73,25 +73,6 @@ // NOMERGE-NEXT: 0000: 61626300 61626300 62630000 14000000 |abc.abc.bc......| // NOMERGE-NEXT: ) -// CHECK: Name: .rodata -// CHECK-NEXT: Type: SHT_PROGBITS -// CHECK-NEXT: Flags [ -// CHECK-NEXT: SHF_ALLOC -// CHECK-NEXT: SHF_MERGE -// CHECK-NEXT: SHF_STRINGS -// CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x1CC -// CHECK-NEXT: Offset: 0x1CC -// CHECK-NEXT: Size: 4 -// CHECK-NEXT: Link: 0 -// CHECK-NEXT: Info: 0 -// CHECK-NEXT: AddressAlignment: 2 -// CHECK-NEXT: EntrySize: 2 -// CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 14000000 |....| -// CHECK-NEXT: ) - - // CHECK: Name: bar // CHECK-NEXT: Value: 0x1C9