Index: lld/trunk/ELF/Driver.cpp =================================================================== --- lld/trunk/ELF/Driver.cpp +++ lld/trunk/ELF/Driver.cpp @@ -1889,8 +1889,7 @@ "feature detected"); } - // This adds a .comment section containing a version string. We have to add it - // before mergeSections because the .comment section is a mergeable section. + // This adds a .comment section containing a version string. if (!config->relocatable) inputSections.push_back(createCommentSection()); @@ -1902,7 +1901,6 @@ splitSections(); markLive(); demoteSharedSymbols(); - mergeSections(); // Make copies of any input sections that need to be copied into each // partition. @@ -1926,6 +1924,16 @@ // they are assigned to output sections by the default rule. Process that. script->addOrphanSections(); + // Migrate InputSectionDescription::sectionBases to sections. This includes + // merging MergeInputSections into a single MergeSyntheticSection. From this + // point onwards InputSectionDescription::sections should be used instead of + // sectionBases. + for (BaseCommand *base : script->sectionCommands) + if (auto *sec = dyn_cast(base)) + sec->finalizeInputSections(); + llvm::erase_if(inputSections, + [](InputSectionBase *s) { return isa(s); }); + // Two input sections with different output sections should not be folded. // ICF runs after processSectionCommands() so that we know the output sections. if (config->icf != ICFLevel::None) { Index: lld/trunk/ELF/LinkerScript.h =================================================================== --- lld/trunk/ELF/LinkerScript.h +++ lld/trunk/ELF/LinkerScript.h @@ -168,6 +168,12 @@ // will be associated with this InputSectionDescription. std::vector sectionPatterns; + // Includes InputSections and MergeInputSections. Used temporarily during + // assignment of input sections to output sections. + std::vector sectionBases; + + // Used after the finalizeInputSections() pass. MergeInputSections have been + // merged into MergeSyntheticSections. std::vector sections; // Temporary record of synthetic ThunkSection instances and the pass that @@ -226,10 +232,10 @@ void expandOutputSection(uint64_t size); void expandMemoryRegions(uint64_t size); - std::vector + std::vector computeInputSections(const InputSectionDescription *); - std::vector createInputSectionList(OutputSection &cmd); + std::vector createInputSectionList(OutputSection &cmd); std::vector getPhdrIndices(OutputSection *sec); @@ -259,7 +265,7 @@ bool hasPhdrsCommands() { return !phdrsCommands.empty(); } uint64_t getDot() { return dot; } - void discard(ArrayRef v); + void discard(InputSectionBase *s); ExprValue getSymbolValue(StringRef name, const Twine &loc); Index: lld/trunk/ELF/LinkerScript.cpp =================================================================== --- lld/trunk/ELF/LinkerScript.cpp +++ lld/trunk/ELF/LinkerScript.cpp @@ -341,19 +341,19 @@ } // A helper function for the SORT() command. -static bool matchConstraints(ArrayRef sections, +static bool matchConstraints(ArrayRef sections, ConstraintKind kind) { if (kind == ConstraintKind::NoConstraint) return true; bool isRW = llvm::any_of( - sections, [](InputSection *sec) { return sec->flags & SHF_WRITE; }); + sections, [](InputSectionBase *sec) { return sec->flags & SHF_WRITE; }); return (isRW && kind == ConstraintKind::ReadWrite) || (!isRW && kind == ConstraintKind::ReadOnly); } -static void sortSections(MutableArrayRef vec, +static void sortSections(MutableArrayRef vec, SortSectionPolicy k) { auto alignmentComparator = [](InputSectionBase *a, InputSectionBase *b) { // ">" is not a mistake. Sections with larger alignments are placed @@ -392,7 +392,7 @@ // --sort-section is handled as an inner SORT command. // 3. If one SORT command is given, and if it is SORT_NONE, don't sort. // 4. If no SORT command is given, sort according to --sort-section. -static void sortInputSections(MutableArrayRef vec, +static void sortInputSections(MutableArrayRef vec, const SectionPattern &pat) { if (pat.sortOuter == SortSectionPolicy::None) return; @@ -405,9 +405,9 @@ } // Compute and remember which sections the InputSectionDescription matches. -std::vector +std::vector LinkerScript::computeInputSections(const InputSectionDescription *cmd) { - std::vector ret; + std::vector ret; // Collects all sections that satisfy constraints of Cmd. for (const SectionPattern &pat : cmd->sectionPatterns) { @@ -422,10 +422,8 @@ // which are common because they are in the default bfd script. // We do not ignore SHT_REL[A] linker-synthesized sections here because // want to support scripts that do custom layout for them. - // - // It is safe to assume that Sec is an InputSection because mergeable or - // EH input sections have already been handled and eliminated. - if (cast(sec)->getRelocatedSection()) + if (isa(sec) && + cast(sec)->getRelocatedSection()) continue; std::string filename = getFilename(sec->file); @@ -434,42 +432,41 @@ !pat.sectionPat.match(sec->name)) continue; - ret.push_back(cast(sec)); + ret.push_back(sec); sec->assigned = true; } - sortInputSections(MutableArrayRef(ret).slice(sizeBefore), - pat); + sortInputSections( + MutableArrayRef(ret).slice(sizeBefore), pat); } return ret; } -void LinkerScript::discard(ArrayRef v) { - for (InputSection *s : v) { - if (s == in.shStrTab || s == mainPart->relaDyn || s == mainPart->relrDyn) - error("discarding " + s->name + " section is not allowed"); - - // You can discard .hash and .gnu.hash sections by linker scripts. Since - // they are synthesized sections, we need to handle them differently than - // other regular sections. - if (s == mainPart->gnuHashTab) - mainPart->gnuHashTab = nullptr; - if (s == mainPart->hashTab) - mainPart->hashTab = nullptr; - - s->markDead(); - discard(s->dependentSections); - } +void LinkerScript::discard(InputSectionBase *s) { + if (s == in.shStrTab || s == mainPart->relaDyn || s == mainPart->relrDyn) + error("discarding " + s->name + " section is not allowed"); + + // You can discard .hash and .gnu.hash sections by linker scripts. Since + // they are synthesized sections, we need to handle them differently than + // other regular sections. + if (s == mainPart->gnuHashTab) + mainPart->gnuHashTab = nullptr; + if (s == mainPart->hashTab) + mainPart->hashTab = nullptr; + + s->markDead(); + for (InputSection *ds : s->dependentSections) + discard(ds); } -std::vector +std::vector LinkerScript::createInputSectionList(OutputSection &outCmd) { - std::vector ret; + std::vector ret; for (BaseCommand *base : outCmd.sectionCommands) { if (auto *cmd = dyn_cast(base)) { - cmd->sections = computeInputSections(cmd); - ret.insert(ret.end(), cmd->sections.begin(), cmd->sections.end()); + cmd->sectionBases = computeInputSections(cmd); + ret.insert(ret.end(), cmd->sectionBases.begin(), cmd->sectionBases.end()); } } return ret; @@ -480,12 +477,13 @@ size_t i = 0; for (BaseCommand *base : sectionCommands) { if (auto *sec = dyn_cast(base)) { - std::vector v = createInputSectionList(*sec); + std::vector v = createInputSectionList(*sec); // The output section name `/DISCARD/' is special. // Any input section assigned to it is discarded. if (sec->name == "/DISCARD/") { - discard(v); + for (InputSectionBase *s : v) + discard(s); sec->sectionCommands.clear(); continue; } @@ -513,15 +511,9 @@ s->alignment = subalign; } - // Some input sections may be removed from the list after ICF. - for (InputSection *s : v) - sec->addSection(s); - sec->sectionIndex = i++; - if (sec->noload) - sec->type = SHT_NOBITS; - if (sec->nonAlloc) - sec->flags &= ~(uint64_t)SHF_ALLOC; + for (InputSectionBase *s : v) + s->parent = sec; } } } @@ -565,7 +557,7 @@ static OutputSection *createSection(InputSectionBase *isec, StringRef outsecName) { OutputSection *sec = script->createOutputSection(outsecName, ""); - sec->addSection(cast(isec)); + sec->recordSection(isec); return sec; } @@ -594,7 +586,7 @@ OutputSection *out = sec->getRelocatedSection()->getOutputSection(); if (out->relocationSection) { - out->relocationSection->addSection(sec); + out->relocationSection->recordSection(sec); return nullptr; } @@ -602,12 +594,6 @@ return out->relocationSection; } - // When control reaches here, mergeable sections have already been merged into - // synthetic sections. For relocatable case we want to create one output - // section per syntetic section so that they have a valid sh_entsize. - if (config->relocatable && (isec->flags & SHF_MERGE)) - return createSection(isec, outsecName); - // The ELF spec just says // ---------------------------------------------------------------- // In the first phase, input sections that match in name, type and @@ -654,7 +640,7 @@ for (OutputSection *sec : v) { if (sec->partition != isec->partition) continue; - sec->addSection(cast(isec)); + sec->recordSection(isec); return nullptr; } @@ -680,13 +666,14 @@ warn(toString(s) + " is being placed in '" + name + "'"); if (OutputSection *sec = findByName(sectionCommands, name)) { - sec->addSection(cast(s)); + sec->recordSection(s); return; } if (OutputSection *os = addInputSec(map, s, name)) v.push_back(os); - assert(s->getOutputSection()->sectionIndex == UINT32_MAX); + assert(isa(s) || + s->getOutputSection()->sectionIndex == UINT32_MAX); }; // For futher --emit-reloc handling code we need target output section Index: lld/trunk/ELF/OutputSections.h =================================================================== --- lld/trunk/ELF/OutputSections.h +++ lld/trunk/ELF/OutputSections.h @@ -71,7 +71,9 @@ uint64_t addr = 0; uint32_t shName = 0; - void addSection(InputSection *isec); + void recordSection(InputSectionBase *isec); + void commitSection(InputSection *isec); + void finalizeInputSections(); // The following members are normally only used in linker scripts. MemoryRegion *memRegion = nullptr; Index: lld/trunk/ELF/OutputSections.cpp =================================================================== --- lld/trunk/ELF/OutputSections.cpp +++ lld/trunk/ELF/OutputSections.cpp @@ -83,12 +83,32 @@ type == SHT_NOTE; } -void OutputSection::addSection(InputSection *isec) { +// Record that isec will be placed in the OutputSection. isec does not become +// permanent until finalizeInputSections() is called. The function should not be +// used after finalizeInputSections() is called. If you need to add an +// InputSection post finalizeInputSections(), then you must do the following: +// +// 1. Find or create an InputSectionDescription to hold InputSection. +// 2. Add the InputSection to the InputSectionDesciption::sections. +// 3. Call commitSection(isec). +void OutputSection::recordSection(InputSectionBase *isec) { + partition = isec->partition; + isec->parent = this; + if (sectionCommands.empty() || + !isa(sectionCommands.back())) + sectionCommands.push_back(make("")); + auto *isd = cast(sectionCommands.back()); + isd->sectionBases.push_back(isec); +} + +// Update fields (type, flags, alignment, etc) according to the InputSection +// isec. Also check whether the InputSection flags and type are consistent with +// other InputSections. +void OutputSection::commitSection(InputSection *isec) { if (!hasInputSections) { // If IS is the first section to be added to this section, - // initialize Partition, Type, Entsize and flags from IS. + // initialize type, entsize and flags from isec. hasInputSections = true; - partition = isec->partition; type = isec->type; entsize = isec->entsize; flags = isec->flags; @@ -110,6 +130,8 @@ type = SHT_PROGBITS; } } + if (noload) + type = SHT_NOBITS; isec->parent = this; uint64_t andMask = @@ -118,6 +140,8 @@ uint64_t andFlags = (flags & isec->flags) & andMask; uint64_t orFlags = (flags | isec->flags) & orMask; flags = andFlags | orFlags; + if (nonAlloc) + flags &= ~(uint64_t)SHF_ALLOC; alignment = std::max(alignment, isec->alignment); @@ -126,15 +150,69 @@ // set sh_entsize to 0. if (entsize != isec->entsize) entsize = 0; +} + +// This function scans over the InputSectionBase list sectionBases to create +// InputSectionDescription::sections. +// +// It removes MergeInputSections from the input section array and adds +// new synthetic sections at the location of the first input section +// that it replaces. It then finalizes each synthetic section in order +// to compute an output offset for each piece of each input section. +void OutputSection::finalizeInputSections() { + std::vector mergeSections; + for (BaseCommand *base : sectionCommands) { + auto *cmd = dyn_cast(base); + if (!cmd) + continue; + cmd->sections.reserve(cmd->sectionBases.size()); + for (InputSectionBase *s : cmd->sectionBases) { + MergeInputSection *ms = dyn_cast(s); + if (!ms) { + cmd->sections.push_back(cast(s)); + continue; + } + + // We do not want to handle sections that are not alive, so just remove + // them instead of trying to merge. + if (!ms->isLive()) + continue; + + auto i = llvm::find_if(mergeSections, [=](MergeSyntheticSection *sec) { + // While we could create a single synthetic section for two different + // values of Entsize, it is better to take Entsize into consideration. + // + // With a single synthetic section no two pieces with different Entsize + // could be equal, so we may as well have two sections. + // + // Using Entsize in here also allows us to propagate it to the synthetic + // section. + // + // SHF_STRINGS section with different alignments should not be merged. + return sec->flags == ms->flags && sec->entsize == ms->entsize && + (sec->alignment == ms->alignment || !(sec->flags & SHF_STRINGS)); + }); + if (i == mergeSections.end()) { + MergeSyntheticSection *syn = + createMergeSynthetic(name, ms->type, ms->flags, ms->alignment); + mergeSections.push_back(syn); + i = std::prev(mergeSections.end()); + syn->entsize = ms->entsize; + cmd->sections.push_back(syn); + } + (*i)->addSection(ms); + } - if (!isec->assigned) { - isec->assigned = true; - if (sectionCommands.empty() || - !isa(sectionCommands.back())) - sectionCommands.push_back(make("")); - auto *isd = cast(sectionCommands.back()); - isd->sections.push_back(isec); + // sectionBases should not be used from this point onwards. Clear it to + // catch misuses. + cmd->sectionBases.clear(); + + // Some input sections may be removed from the list after ICF. + for (InputSection *s : cmd->sections) + commitSection(s); } + for (auto *ms : mergeSections) + ms->finalizeContents(); } static void sortByOrder(MutableArrayRef in, Index: lld/trunk/ELF/Relocations.cpp =================================================================== --- lld/trunk/ELF/Relocations.cpp +++ lld/trunk/ELF/Relocations.cpp @@ -567,10 +567,16 @@ bool isRO = isReadOnly(ss); BssSection *sec = make(isRO ? ".bss.rel.ro" : ".bss", symSize, ss.alignment); - if (isRO) - in.bssRelRo->getParent()->addSection(sec); - else - in.bss->getParent()->addSection(sec); + OutputSection *osec = (isRO ? in.bssRelRo : in.bss)->getParent(); + + // At this point, sectionBases has been migrated to sections. Append sec to + // sections. + if (osec->sectionCommands.empty() || + !isa(osec->sectionCommands.back())) + osec->sectionCommands.push_back(make("")); + auto *isd = cast(osec->sectionCommands.back()); + isd->sections.push_back(sec); + osec->commitSection(sec); // Look through the DSO's dynamic symbol table for aliases and create a // dynamic symbol for each one. This causes the copy relocation to correctly Index: lld/trunk/ELF/SyntheticSections.h =================================================================== --- lld/trunk/ELF/SyntheticSections.h +++ lld/trunk/ELF/SyntheticSections.h @@ -1102,8 +1102,9 @@ InputSection *createInterpSection(); MergeInputSection *createCommentSection(); +MergeSyntheticSection *createMergeSynthetic(StringRef name, uint32_t type, + uint64_t flags, uint32_t alignment); template void splitSections(); -void mergeSections(); template void writeEhdr(uint8_t *buf, Partition &part); template void writePhdrs(uint8_t *buf, Partition &part); Index: lld/trunk/ELF/SyntheticSections.cpp =================================================================== --- lld/trunk/ELF/SyntheticSections.cpp +++ lld/trunk/ELF/SyntheticSections.cpp @@ -3125,10 +3125,9 @@ }); } -static MergeSyntheticSection *createMergeSynthetic(StringRef name, - uint32_t type, - uint64_t flags, - uint32_t alignment) { +MergeSyntheticSection *elf::createMergeSynthetic(StringRef name, uint32_t type, + uint64_t flags, + uint32_t alignment) { bool shouldTailMerge = (flags & SHF_STRINGS) && config->optimize >= 2; if (shouldTailMerge) return make(name, type, flags, alignment); @@ -3146,63 +3145,6 @@ }); } -// This function scans over the inputsections to create mergeable -// synthetic sections. -// -// It removes MergeInputSections from the input section array and adds -// new synthetic sections at the location of the first input section -// that it replaces. It then finalizes each synthetic section in order -// to compute an output offset for each piece of each input section. -void elf::mergeSections() { - std::vector mergeSections; - for (InputSectionBase *&s : inputSections) { - MergeInputSection *ms = dyn_cast(s); - if (!ms) - continue; - - // We do not want to handle sections that are not alive, so just remove - // them instead of trying to merge. - if (!ms->isLive()) { - s = nullptr; - continue; - } - - StringRef outsecName = getOutputSectionName(ms); - - auto i = llvm::find_if(mergeSections, [=](MergeSyntheticSection *sec) { - // While we could create a single synthetic section for two different - // values of Entsize, it is better to take Entsize into consideration. - // - // With a single synthetic section no two pieces with different Entsize - // could be equal, so we may as well have two sections. - // - // Using Entsize in here also allows us to propagate it to the synthetic - // section. - // - // SHF_STRINGS section with different alignments should not be merged. - return sec->name == outsecName && sec->flags == ms->flags && - sec->entsize == ms->entsize && - (sec->alignment == ms->alignment || !(sec->flags & SHF_STRINGS)); - }); - if (i == mergeSections.end()) { - MergeSyntheticSection *syn = - createMergeSynthetic(outsecName, ms->type, ms->flags, ms->alignment); - mergeSections.push_back(syn); - i = std::prev(mergeSections.end()); - s = syn; - syn->entsize = ms->entsize; - } else { - s = nullptr; - } - (*i)->addSection(ms); - } - for (auto *ms : mergeSections) - ms->finalizeContents(); - - std::vector &v = inputSections; - v.erase(std::remove(v.begin(), v.end(), nullptr), v.end()); -} - MipsRldMapSection::MipsRldMapSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize, ".rld_map") {} Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -705,7 +705,7 @@ }); if (i == sec->sectionCommands.end()) continue; - InputSection *isec = cast(*i)->sections[0]; + InputSectionBase *isec = cast(*i)->sections[0]; // Relocations are not using REL[A] section symbols. if (isec->type == SHT_REL || isec->type == SHT_RELA) Index: lld/trunk/test/ELF/linkerscript/merge-output-sections.s =================================================================== --- lld/trunk/test/ELF/linkerscript/merge-output-sections.s +++ lld/trunk/test/ELF/linkerscript/merge-output-sections.s @@ -0,0 +1,35 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o + +## SHF_MERGE sections within the same output section can be freely merged. +# RUN: echo 'SECTIONS { .rodata : { *(.rodata.*) }}' > %t.script +# RUN: ld.lld %t.o -T %t.script -o %t +# RUN: llvm-readelf -x .rodata %t | FileCheck --check-prefix=SAME %s --implicit-check-not=section + +# SAME: section '.rodata': +# SAME-NEXT: 0x00000000 01000200 0300 + +## SHF_MERGE sections with different output sections cannot be merged. +# RUN: echo 'SECTIONS { \ +# RUN: .rodata.foo : { *(.rodata.foo) } \ +# RUN: .rodata.bar : { *(.rodata.bar) } \ +# RUN: }' > %t2.script +# RUN: ld.lld %t.o -T %t2.script -o %t2 +# RUN: llvm-readelf -x .rodata.foo -x .rodata.bar %t2 | FileCheck --check-prefix=DIFF %s --implicit-check-not=section + +# DIFF: section '.rodata.foo': +# DIFF-NEXT: 0x00000000 01000200 0300 +# DIFF: section '.rodata.bar': +# DIFF-NEXT: 0x00000006 0100 + +.section .rodata.foo,"aM",@progbits,2,unique,0 +.short 1 +.short 2 +.section .rodata.foo,"aM",@progbits,2,unique,1 +.short 1 +.short 3 + +.section .rodata.bar,"aM",@progbits,2,unique,0 +.short 1 +.section .rodata.bar,"aM",@progbits,2,unique,1 +.short 1 Index: lld/trunk/test/ELF/linkerscript/merge-sections.s =================================================================== --- lld/trunk/test/ELF/linkerscript/merge-sections.s +++ lld/trunk/test/ELF/linkerscript/merge-sections.s @@ -17,7 +17,7 @@ # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x[[ADDR1:.*]] # CHECK-NEXT: Offset: 0x[[ADDR1]] -# CHECK-NEXT: Size: 14 +# CHECK-NEXT: Size: 8 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 2 @@ -28,7 +28,7 @@ # CHECK-NEXT: Value: 0x[[ADDR1]] # CHECK: Name: end -# CHECK-NEXT: Value: 0x236 +# CHECK-NEXT: Value: 0x230 # Check that we don't crash with --gc-sections # RUN: ld.lld --gc-sections -o %t2 --script %t.script %t -shared Index: lld/trunk/test/ELF/merge-entsize2.s =================================================================== --- lld/trunk/test/ELF/merge-entsize2.s +++ lld/trunk/test/ELF/merge-entsize2.s @@ -6,8 +6,8 @@ # RUN: llvm-readelf -x .cst %t | FileCheck --check-prefix=HEX %s # RUN: ld.lld -O0 -r %t.o -o %t1.o -# RUN: llvm-readelf -S %t1.o | FileCheck --check-prefix=SEC-R %s -# RUN: llvm-readelf -x .cst %t1.o | FileCheck --check-prefix=HEX-R %s +# RUN: llvm-readelf -S %t1.o | FileCheck --check-prefix=SEC %s +# RUN: llvm-readelf -x .cst %t1.o | FileCheck --check-prefix=HEX %s ## Check that SHF_MERGE sections with the same name, sh_flags and sh_entsize ## are grouped together and can be merged within the group. @@ -17,20 +17,10 @@ # SEC: Name Type {{.*}} Size ES Flg Lk Inf Al # SEC: .cst PROGBITS {{.*}} 000020 00 AM 0 0 8 -## .cst 0 and .cst 1 are merged, but emitted as a separate output section. -# SEC-R: .cst PROGBITS {{.*}} 00000c 04 AM 0 0 4 -# SEC-R: .cst PROGBITS {{.*}} 000010 08 AM 0 0 8 - # HEX: Hex dump of section '.cst': # HEX-NEXT: 0x{{[0-9a-f]+}} 01000000 00000000 02000000 00000000 # HEX-NEXT: 0x{{[0-9a-f]+}} 01000000 00000000 03000000 00000000 -# HEX-R: Hex dump of section '.cst': -# HEX-R-NEXT: 0x00000000 01000000 00000000 02000000 -# HEX-R-EMPTY: -# HEX-R-NEXT: Hex dump of section '.cst': -# HEX-R-NEXT: 0x00000000 01000000 00000000 03000000 00000000 - .section .cst,"aM",@progbits,4,unique,0 .align 2 .long 1