| commit e47bbd28f8e9dfea4e019e27e9d371c144c3302e |
| Author: Fangrui Song <maskray@google.com> |
| Date: Tue Sep 24 11:48:31 2019 +0000 |
| |
| [ELF] Make MergeInputSection merging aware of output sections |
| |
| Fixes PR38748 |
| |
| mergeSections() calls getOutputSectionName() to get output section |
| names. Two MergeInputSections may be merged even if they are made |
| different by SECTIONS commands. |
| |
| This patch moves mergeSections() after processSectionCommands() and |
| addOrphanSections() to fix the issue. The new pass is renamed to |
| OutputSection::finalizeInputSections(). |
| |
| processSectionCommands() and addorphanSections() are changed to add |
| sections to InputSectionDescription::sectionBases. |
| |
| finalizeInputSections() merges MergeInputSections and migrates |
| `sectionBases` to `sections`. |
| |
| For the -r case, we drop an optimization that tries keeping sh_entsize |
| non-zero. This is for the simplicity of addOrphanSections(). The |
| updated merge-entsize2.s reflects the change. |
| |
| Reviewed By: grimar |
| |
| Differential Revision: https://reviews.llvm.org/D67504 |
| |
| llvm-svn: 372734 |
| |
| diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp |
| index bae04791ec4..f4a4d1d3fd1 100644 |
| --- a/lld/ELF/Driver.cpp |
| +++ b/lld/ELF/Driver.cpp |
| @@ -1889,8 +1889,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { |
| "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 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { |
| splitSections<ELFT>(); |
| markLive<ELFT>(); |
| demoteSharedSymbols(); |
| - mergeSections(); |
| |
| // Make copies of any input sections that need to be copied into each |
| // partition. |
| @@ -1926,6 +1924,16 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { |
| // 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<OutputSection>(base)) |
| + sec->finalizeInputSections(); |
| + llvm::erase_if(inputSections, |
| + [](InputSectionBase *s) { return isa<MergeInputSection>(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) { |
| diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp |
| index cd02e779e7a..48f6c38cce6 100644 |
| --- a/lld/ELF/LinkerScript.cpp |
| +++ b/lld/ELF/LinkerScript.cpp |
| @@ -341,19 +341,19 @@ bool LinkerScript::shouldKeep(InputSectionBase *s) { |
| } |
| |
| // A helper function for the SORT() command. |
| -static bool matchConstraints(ArrayRef<InputSection *> sections, |
| +static bool matchConstraints(ArrayRef<InputSectionBase *> 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<InputSection *> vec, |
| +static void sortSections(MutableArrayRef<InputSectionBase *> vec, |
| SortSectionPolicy k) { |
| auto alignmentComparator = [](InputSectionBase *a, InputSectionBase *b) { |
| // ">" is not a mistake. Sections with larger alignments are placed |
| @@ -392,7 +392,7 @@ static void sortSections(MutableArrayRef<InputSection *> vec, |
| // --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<InputSection *> vec, |
| +static void sortInputSections(MutableArrayRef<InputSectionBase *> vec, |
| const SectionPattern &pat) { |
| if (pat.sortOuter == SortSectionPolicy::None) |
| return; |
| @@ -405,9 +405,9 @@ static void sortInputSections(MutableArrayRef<InputSection *> vec, |
| } |
| |
| // Compute and remember which sections the InputSectionDescription matches. |
| -std::vector<InputSection *> |
| +std::vector<InputSectionBase *> |
| LinkerScript::computeInputSections(const InputSectionDescription *cmd) { |
| - std::vector<InputSection *> ret; |
| + std::vector<InputSectionBase *> ret; |
| |
| // Collects all sections that satisfy constraints of Cmd. |
| for (const SectionPattern &pat : cmd->sectionPatterns) { |
| @@ -422,10 +422,8 @@ LinkerScript::computeInputSections(const InputSectionDescription *cmd) { |
| // 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<InputSection>(sec)->getRelocatedSection()) |
| + if (isa<InputSection>(sec) && |
| + cast<InputSection>(sec)->getRelocatedSection()) |
| continue; |
| |
| std::string filename = getFilename(sec->file); |
| @@ -434,42 +432,41 @@ LinkerScript::computeInputSections(const InputSectionDescription *cmd) { |
| !pat.sectionPat.match(sec->name)) |
| continue; |
| |
| - ret.push_back(cast<InputSection>(sec)); |
| + ret.push_back(sec); |
| sec->assigned = true; |
| } |
| |
| - sortInputSections(MutableArrayRef<InputSection *>(ret).slice(sizeBefore), |
| - pat); |
| + sortInputSections( |
| + MutableArrayRef<InputSectionBase *>(ret).slice(sizeBefore), pat); |
| } |
| return ret; |
| } |
| |
| -void LinkerScript::discard(ArrayRef<InputSection *> 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<InputSection *> |
| +std::vector<InputSectionBase *> |
| LinkerScript::createInputSectionList(OutputSection &outCmd) { |
| - std::vector<InputSection *> ret; |
| + std::vector<InputSectionBase *> ret; |
| |
| for (BaseCommand *base : outCmd.sectionCommands) { |
| if (auto *cmd = dyn_cast<InputSectionDescription>(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 @@ void LinkerScript::processSectionCommands() { |
| size_t i = 0; |
| for (BaseCommand *base : sectionCommands) { |
| if (auto *sec = dyn_cast<OutputSection>(base)) { |
| - std::vector<InputSection *> v = createInputSectionList(*sec); |
| + std::vector<InputSectionBase *> 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 @@ void LinkerScript::processSectionCommands() { |
| 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 *findByName(ArrayRef<BaseCommand *> vec, |
| static OutputSection *createSection(InputSectionBase *isec, |
| StringRef outsecName) { |
| OutputSection *sec = script->createOutputSection(outsecName, "<internal>"); |
| - sec->addSection(cast<InputSection>(isec)); |
| + sec->recordSection(isec); |
| return sec; |
| } |
| |
| @@ -594,7 +586,7 @@ addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map, |
| OutputSection *out = sec->getRelocatedSection()->getOutputSection(); |
| |
| if (out->relocationSection) { |
| - out->relocationSection->addSection(sec); |
| + out->relocationSection->recordSection(sec); |
| return nullptr; |
| } |
| |
| @@ -602,12 +594,6 @@ addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map, |
| 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 @@ addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map, |
| for (OutputSection *sec : v) { |
| if (sec->partition != isec->partition) |
| continue; |
| - sec->addSection(cast<InputSection>(isec)); |
| + sec->recordSection(isec); |
| return nullptr; |
| } |
| |
| @@ -680,13 +666,14 @@ void LinkerScript::addOrphanSections() { |
| warn(toString(s) + " is being placed in '" + name + "'"); |
| |
| if (OutputSection *sec = findByName(sectionCommands, name)) { |
| - sec->addSection(cast<InputSection>(s)); |
| + sec->recordSection(s); |
| return; |
| } |
| |
| if (OutputSection *os = addInputSec(map, s, name)) |
| v.push_back(os); |
| - assert(s->getOutputSection()->sectionIndex == UINT32_MAX); |
| + assert(isa<MergeInputSection>(s) || |
| + s->getOutputSection()->sectionIndex == UINT32_MAX); |
| }; |
| |
| // For futher --emit-reloc handling code we need target output section |
| diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h |
| index 4ac9e2a3909..621b8baeaae 100644 |
| --- a/lld/ELF/LinkerScript.h |
| +++ b/lld/ELF/LinkerScript.h |
| @@ -168,6 +168,12 @@ struct InputSectionDescription : BaseCommand { |
| // will be associated with this InputSectionDescription. |
| std::vector<SectionPattern> sectionPatterns; |
| |
| + // Includes InputSections and MergeInputSections. Used temporarily during |
| + // assignment of input sections to output sections. |
| + std::vector<InputSectionBase *> sectionBases; |
| + |
| + // Used after the finalizeInputSections() pass. MergeInputSections have been |
| + // merged into MergeSyntheticSections. |
| std::vector<InputSection *> sections; |
| |
| // Temporary record of synthetic ThunkSection instances and the pass that |
| @@ -226,10 +232,10 @@ class LinkerScript final { |
| void expandOutputSection(uint64_t size); |
| void expandMemoryRegions(uint64_t size); |
| |
| - std::vector<InputSection *> |
| + std::vector<InputSectionBase *> |
| computeInputSections(const InputSectionDescription *); |
| |
| - std::vector<InputSection *> createInputSectionList(OutputSection &cmd); |
| + std::vector<InputSectionBase *> createInputSectionList(OutputSection &cmd); |
| |
| std::vector<size_t> getPhdrIndices(OutputSection *sec); |
| |
| @@ -259,7 +265,7 @@ public: |
| |
| bool hasPhdrsCommands() { return !phdrsCommands.empty(); } |
| uint64_t getDot() { return dot; } |
| - void discard(ArrayRef<InputSection *> v); |
| + void discard(InputSectionBase *s); |
| |
| ExprValue getSymbolValue(StringRef name, const Twine &loc); |
| |
| diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp |
| index a89bd509bc9..d6164103867 100644 |
| --- a/lld/ELF/OutputSections.cpp |
| +++ b/lld/ELF/OutputSections.cpp |
| @@ -83,12 +83,32 @@ static bool canMergeToProgbits(unsigned type) { |
| 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<InputSectionDescription>(sectionCommands.back())) |
| + sectionCommands.push_back(make<InputSectionDescription>("")); |
| + auto *isd = cast<InputSectionDescription>(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 @@ void OutputSection::addSection(InputSection *isec) { |
| type = SHT_PROGBITS; |
| } |
| } |
| + if (noload) |
| + type = SHT_NOBITS; |
| |
| isec->parent = this; |
| uint64_t andMask = |
| @@ -118,6 +140,8 @@ void OutputSection::addSection(InputSection *isec) { |
| 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 @@ void OutputSection::addSection(InputSection *isec) { |
| // 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<MergeSyntheticSection *> mergeSections; |
| + for (BaseCommand *base : sectionCommands) { |
| + auto *cmd = dyn_cast<InputSectionDescription>(base); |
| + if (!cmd) |
| + continue; |
| + cmd->sections.reserve(cmd->sectionBases.size()); |
| + for (InputSectionBase *s : cmd->sectionBases) { |
| + MergeInputSection *ms = dyn_cast<MergeInputSection>(s); |
| + if (!ms) { |
| + cmd->sections.push_back(cast<InputSection>(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); |
| + } |
| + |
| + // sectionBases should not be used from this point onwards. Clear it to |
| + // catch misuses. |
| + cmd->sectionBases.clear(); |
| |
| - if (!isec->assigned) { |
| - isec->assigned = true; |
| - if (sectionCommands.empty() || |
| - !isa<InputSectionDescription>(sectionCommands.back())) |
| - sectionCommands.push_back(make<InputSectionDescription>("")); |
| - auto *isd = cast<InputSectionDescription>(sectionCommands.back()); |
| - isd->sections.push_back(isec); |
| + // 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<InputSection *> in, |
| diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h |
| index fff8327ea37..a24294eedf3 100644 |
| --- a/lld/ELF/OutputSections.h |
| +++ b/lld/ELF/OutputSections.h |
| @@ -71,7 +71,9 @@ public: |
| 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; |
| diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp |
| index 42f0a873909..442ffdbb2f8 100644 |
| --- a/lld/ELF/Relocations.cpp |
| +++ b/lld/ELF/Relocations.cpp |
| @@ -567,10 +567,16 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol &ss) { |
| bool isRO = isReadOnly<ELFT>(ss); |
| BssSection *sec = |
| make<BssSection>(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<InputSectionDescription>(osec->sectionCommands.back())) |
| + osec->sectionCommands.push_back(make<InputSectionDescription>("")); |
| + auto *isd = cast<InputSectionDescription>(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 |
| diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp |
| index e323ecaa9d7..1948da93095 100644 |
| --- a/lld/ELF/SyntheticSections.cpp |
| +++ b/lld/ELF/SyntheticSections.cpp |
| @@ -3125,10 +3125,9 @@ void MergeNoTailSection::finalizeContents() { |
| }); |
| } |
| |
| -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<MergeTailSection>(name, type, flags, alignment); |
| @@ -3146,63 +3145,6 @@ template <class ELFT> void elf::splitSections() { |
| }); |
| } |
| |
| -// 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<MergeSyntheticSection *> mergeSections; |
| - for (InputSectionBase *&s : inputSections) { |
| - MergeInputSection *ms = dyn_cast<MergeInputSection>(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<InputSectionBase *> &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") {} |
| diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h |
| index 68463978950..7442f33f0b0 100644 |
| --- a/lld/ELF/SyntheticSections.h |
| +++ b/lld/ELF/SyntheticSections.h |
| @@ -1102,8 +1102,9 @@ public: |
| |
| InputSection *createInterpSection(); |
| MergeInputSection *createCommentSection(); |
| +MergeSyntheticSection *createMergeSynthetic(StringRef name, uint32_t type, |
| + uint64_t flags, uint32_t alignment); |
| template <class ELFT> void splitSections(); |
| -void mergeSections(); |
| |
| template <typename ELFT> void writeEhdr(uint8_t *buf, Partition &part); |
| template <typename ELFT> void writePhdrs(uint8_t *buf, Partition &part); |
| diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp |
| index f0334470e5e..1a5504b2624 100644 |
| --- a/lld/ELF/Writer.cpp |
| +++ b/lld/ELF/Writer.cpp |
| @@ -705,7 +705,7 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() { |
| }); |
| if (i == sec->sectionCommands.end()) |
| continue; |
| - InputSection *isec = cast<InputSectionDescription>(*i)->sections[0]; |
| + InputSectionBase *isec = cast<InputSectionDescription>(*i)->sections[0]; |
| |
| // Relocations are not using REL[A] section symbols. |
| if (isec->type == SHT_REL || isec->type == SHT_RELA) |
| diff --git a/lld/test/ELF/linkerscript/merge-output-sections.s b/lld/test/ELF/linkerscript/merge-output-sections.s |
| new file mode 100644 |
| index 00000000000..b15596f84cf |
| --- /dev/null |
| +++ b/lld/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 |
| diff --git a/lld/test/ELF/linkerscript/merge-sections.s b/lld/test/ELF/linkerscript/merge-sections.s |
| index b9ebfe79714..ea53ba3e420 100644 |
| --- a/lld/test/ELF/linkerscript/merge-sections.s |
| +++ b/lld/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 |
| diff --git a/lld/test/ELF/merge-entsize2.s b/lld/test/ELF/merge-entsize2.s |
| index 26e40d3a55e..25036beeea8 100644 |
| --- a/lld/test/ELF/merge-entsize2.s |
| +++ b/lld/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 |