diff options
Diffstat (limited to 'contrib/llvm-project/lld/ELF/OutputSections.cpp')
-rw-r--r-- | contrib/llvm-project/lld/ELF/OutputSections.cpp | 114 |
1 files changed, 97 insertions, 17 deletions
diff --git a/contrib/llvm-project/lld/ELF/OutputSections.cpp b/contrib/llvm-project/lld/ELF/OutputSections.cpp index a89bd509bc96..ea7c96eb676a 100644 --- a/contrib/llvm-project/lld/ELF/OutputSections.cpp +++ b/contrib/llvm-project/lld/ELF/OutputSections.cpp @@ -27,9 +27,8 @@ using namespace llvm::object; using namespace llvm::support::endian; using namespace llvm::ELF; -using namespace lld; -using namespace lld::elf; - +namespace lld { +namespace elf { uint8_t *Out::bufferStart; uint8_t Out::first; PhdrEntry *Out::tlsPhdr; @@ -39,7 +38,7 @@ OutputSection *Out::preinitArray; OutputSection *Out::initArray; OutputSection *Out::finiArray; -std::vector<OutputSection *> elf::outputSections; +std::vector<OutputSection *> outputSections; uint32_t OutputSection::getPhdrFlags() const { uint32_t ret = 0; @@ -83,12 +82,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 +129,8 @@ void OutputSection::addSection(InputSection *isec) { type = SHT_PROGBITS; } } + if (noload) + type = SHT_NOBITS; isec->parent = this; uint64_t andMask = @@ -118,6 +139,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 +149,69 @@ void OutputSection::addSection(InputSection *isec) { // set sh_entsize to 0. if (entsize != isec->entsize) entsize = 0; +} - 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); +// 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(); + + // 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, @@ -148,7 +225,7 @@ static void sortByOrder(MutableArrayRef<InputSection *> in, in[i] = v[i].second; } -uint64_t elf::getHeaderSize() { +uint64_t getHeaderSize() { if (config->oFormatBinary) return 0; return Out::elfHeader->size + Out::programHeaders->size; @@ -368,7 +445,7 @@ void OutputSection::sortCtorsDtors() { // If an input string is in the form of "foo.N" where N is a number, // return N. Otherwise, returns 65536, which is one greater than the // lowest priority. -int elf::getPriority(StringRef s) { +int getPriority(StringRef s) { size_t pos = s.rfind('.'); if (pos == StringRef::npos) return 65536; @@ -378,7 +455,7 @@ int elf::getPriority(StringRef s) { return v; } -std::vector<InputSection *> elf::getInputSections(OutputSection *os) { +std::vector<InputSection *> getInputSections(OutputSection *os) { std::vector<InputSection *> ret; for (BaseCommand *base : os->sectionCommands) if (auto *isd = dyn_cast<InputSectionDescription>(base)) @@ -419,3 +496,6 @@ template void OutputSection::maybeCompress<ELF32LE>(); template void OutputSection::maybeCompress<ELF32BE>(); template void OutputSection::maybeCompress<ELF64LE>(); template void OutputSection::maybeCompress<ELF64BE>(); + +} // namespace elf +} // namespace lld |