diff options
-rw-r--r-- | lld/ELF/Config.h | 1 | ||||
-rw-r--r-- | lld/ELF/Driver.cpp | 4 | ||||
-rw-r--r-- | lld/ELF/InputSection.cpp | 7 | ||||
-rw-r--r-- | lld/ELF/InputSection.h | 25 | ||||
-rw-r--r-- | lld/ELF/LinkerScript.cpp | 181 | ||||
-rw-r--r-- | lld/ELF/LinkerScript.h | 15 | ||||
-rw-r--r-- | lld/ELF/Options.td | 3 | ||||
-rw-r--r-- | lld/ELF/OutputSections.cpp | 7 | ||||
-rw-r--r-- | lld/ELF/OutputSections.h | 2 | ||||
-rw-r--r-- | lld/ELF/SyntheticSections.cpp | 7 | ||||
-rw-r--r-- | lld/ELF/SyntheticSections.h | 4 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 22 | ||||
-rw-r--r-- | lld/docs/ELF/linker_script.rst | 11 | ||||
-rw-r--r-- | lld/docs/ReleaseNotes.rst | 6 | ||||
-rw-r--r-- | lld/docs/ld.lld.1 | 2 | ||||
-rw-r--r-- | lld/test/ELF/linkerscript/enable-non-contiguous-regions-arm-exidx.test | 55 | ||||
-rw-r--r-- | lld/test/ELF/linkerscript/enable-non-contiguous-regions.test | 265 |
17 files changed, 17 insertions, 600 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index dbb8141..c55b547 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -238,7 +238,6 @@ struct Config { bool emitLLVM; bool emitRelocs; bool enableNewDtags; - bool enableNonContiguousRegions; bool executeOnly; bool exportDynamic; bool fixCortexA53Errata843419; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 828499f..dd33f4b 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1250,8 +1250,6 @@ static void readConfigs(opt::InputArgList &args) { config->emitRelocs = args.hasArg(OPT_emit_relocs); config->enableNewDtags = args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true); - config->enableNonContiguousRegions = - args.hasArg(OPT_enable_non_contiguous_regions); config->entry = args.getLastArgValue(OPT_entry); errorHandler().errorHandlingScript = @@ -3087,7 +3085,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { // sectionBases. for (SectionCommand *cmd : script->sectionCommands) if (auto *osd = dyn_cast<OutputDesc>(cmd)) - osd->osec.finalizeInputSections(script.get()); + osd->osec.finalizeInputSections(); } // Two input sections with different output sections should not be folded. diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 2a1ccd9..fa81611 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -161,7 +161,6 @@ uint64_t SectionBase::getOffset(uint64_t offset) const { } case Regular: case Synthetic: - case Spill: return cast<InputSection>(this)->outSecOff + offset; case EHFrame: { // Two code paths may reach here. First, clang_rt.crtbegin.o and GCC @@ -310,12 +309,6 @@ std::string InputSectionBase::getObjMsg(uint64_t off) const { .str(); } -PotentialSpillSection::PotentialSpillSection(const InputSectionBase &source, - InputSectionDescription &isd) - : InputSection(source.file, source.flags, source.type, source.addralign, {}, - source.name, SectionBase::Spill), - isd(&isd) {} - InputSection InputSection::discarded(nullptr, 0, 0, 0, ArrayRef<uint8_t>(), ""); InputSection::InputSection(InputFile *f, uint64_t flags, uint32_t type, diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index 58e5306..1fb7077 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -48,7 +48,7 @@ template <class ELFT> struct RelsOrRelas { // sections. class SectionBase { public: - enum Kind { Regular, Synthetic, Spill, EHFrame, Merge, Output }; + enum Kind { Regular, Synthetic, EHFrame, Merge, Output }; Kind kind() const { return (Kind)sectionKind; } @@ -382,8 +382,7 @@ public: static bool classof(const SectionBase *s) { return s->kind() == SectionBase::Regular || - s->kind() == SectionBase::Synthetic || - s->kind() == SectionBase::Spill; + s->kind() == SectionBase::Synthetic; } // Write this section to a mmap'ed file, assuming Buf is pointing to @@ -426,26 +425,6 @@ private: template <class ELFT> void copyShtGroup(uint8_t *buf); }; -// A marker for a potential spill location for another input section. This -// broadly acts as if it were the original section until address assignment. -// Then it is either replaced with the real input section or removed. -class PotentialSpillSection : public InputSection { -public: - // The containing input section description; used to quickly replace this stub - // with the actual section. - InputSectionDescription *isd; - - // Next potential spill location for the same source input section. - PotentialSpillSection *next = nullptr; - - PotentialSpillSection(const InputSectionBase &source, - InputSectionDescription &isd); - - static bool classof(const SectionBase *sec) { - return sec->kind() == InputSectionBase::Spill; - } -}; - static_assert(sizeof(InputSection) <= 160, "InputSection is too big"); class SyntheticSection : public InputSection { diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 3ba59c1..c0a5014 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -304,9 +304,6 @@ getChangedSymbolAssignment(const SymbolAssignmentMap &oldValues) { void LinkerScript::processInsertCommands() { SmallVector<OutputDesc *, 0> moves; for (const InsertCommand &cmd : insertCommands) { - if (config->enableNonContiguousRegions) - error("INSERT cannot be used with --enable-non-contiguous-regions"); - for (StringRef name : cmd.names) { // If base is empty, it may have been discarded by // adjustOutputSections(). We do not handle such output sections. @@ -489,12 +486,10 @@ static void sortInputSections(MutableArrayRef<InputSectionBase *> vec, // Compute and remember which sections the InputSectionDescription matches. SmallVector<InputSectionBase *, 0> LinkerScript::computeInputSections(const InputSectionDescription *cmd, - ArrayRef<InputSectionBase *> sections, - const OutputSection &outCmd) { + ArrayRef<InputSectionBase *> sections) { SmallVector<InputSectionBase *, 0> ret; SmallVector<size_t, 0> indexes; DenseSet<size_t> seen; - DenseSet<InputSectionBase *> spills; auto sortByPositionThenCommandLine = [&](size_t begin, size_t end) { llvm::sort(MutableArrayRef<size_t>(indexes).slice(begin, end - begin)); for (size_t i = begin; i != end; ++i) @@ -510,10 +505,10 @@ LinkerScript::computeInputSections(const InputSectionDescription *cmd, size_t sizeBeforeCurrPat = ret.size(); for (size_t i = 0, e = sections.size(); i != e; ++i) { - // Skip if the section is dead or has been matched by a previous pattern - // in this input section description. + // Skip if the section is dead or has been matched by a previous input + // section description or a previous pattern. InputSectionBase *sec = sections[i]; - if (!sec->isLive() || seen.contains(i)) + if (!sec->isLive() || sec->parent || seen.contains(i)) continue; // For --emit-relocs we have to ignore entries like @@ -534,29 +529,6 @@ LinkerScript::computeInputSections(const InputSectionDescription *cmd, (sec->flags & cmd->withoutFlags) != 0) continue; - if (sec->parent) { - // Skip if not allowing multiple matches. - if (!config->enableNonContiguousRegions) - continue; - - // Disallow spilling into /DISCARD/; special handling would be needed - // for this in address assignment, and the semantics are nebulous. - if (outCmd.name == "/DISCARD/") - continue; - - // Skip if the section's first match was /DISCARD/; such sections are - // always discarded. - if (sec->parent->name == "/DISCARD/") - continue; - - // Skip if the section was already matched by a different input section - // description within this output section. - if (sec->parent == &outCmd) - continue; - - spills.insert(sec); - } - ret.push_back(sec); indexes.push_back(i); seen.insert(i); @@ -583,30 +555,6 @@ LinkerScript::computeInputSections(const InputSectionDescription *cmd, // Matched sections after the last SORT* are sorted by (--sort-alignment, // input order). sortByPositionThenCommandLine(sizeAfterPrevSort, ret.size()); - - // The flag --enable-non-contiguous-regions may cause sections to match an - // InputSectionDescription in more than one OutputSection. Matches after the - // first were collected in the spills set, so replace these with potential - // spill sections. - if (!spills.empty()) { - for (InputSectionBase *&sec : ret) { - if (!spills.contains(sec)) - continue; - - // Append the spill input section to the list for the input section, - // creating it if necessary. - PotentialSpillSection *pss = make<PotentialSpillSection>( - *sec, const_cast<InputSectionDescription &>(*cmd)); - auto [it, inserted] = - potentialSpillLists.try_emplace(sec, PotentialSpillList{pss, pss}); - if (!inserted) { - PotentialSpillSection *&tail = it->second.tail; - tail = tail->next = pss; - } - sec = pss; - } - } - return ret; } @@ -629,7 +577,7 @@ void LinkerScript::discardSynthetic(OutputSection &outCmd) { part.armExidx->exidxSections.end()); for (SectionCommand *cmd : outCmd.commands) if (auto *isd = dyn_cast<InputSectionDescription>(cmd)) - for (InputSectionBase *s : computeInputSections(isd, secs, outCmd)) + for (InputSectionBase *s : computeInputSections(isd, secs)) discard(*s); } } @@ -640,7 +588,7 @@ LinkerScript::createInputSectionList(OutputSection &outCmd) { for (SectionCommand *cmd : outCmd.commands) { if (auto *isd = dyn_cast<InputSectionDescription>(cmd)) { - isd->sectionBases = computeInputSections(isd, ctx.inputSections, outCmd); + isd->sectionBases = computeInputSections(isd, ctx.inputSections); for (InputSectionBase *s : isd->sectionBases) s->parent = &outCmd; ret.insert(ret.end(), isd->sectionBases.begin(), isd->sectionBases.end()); @@ -696,9 +644,6 @@ void LinkerScript::processSectionCommands() { // Process OVERWRITE_SECTIONS first so that it can overwrite the main script // or orphans. - if (config->enableNonContiguousRegions && !overwriteSections.empty()) - error("OVERWRITE_SECTIONS cannot be used with " - "--enable-non-contiguous-regions"); DenseMap<CachedHashStringRef, OutputDesc *> map; size_t i = 0; for (OutputDesc *osd : overwriteSections) { @@ -1121,12 +1066,8 @@ void LinkerScript::assignOffsets(OutputSection *sec) { // Handle a single input section description command. // It calculates and assigns the offsets for each section and also // updates the output section size. - - auto §ions = cast<InputSectionDescription>(cmd)->sections; - for (InputSection *isec : sections) { + for (InputSection *isec : cast<InputSectionDescription>(cmd)->sections) { assert(isec->getParent() == sec); - if (isa<PotentialSpillSection>(isec)) - continue; const uint64_t pos = dot; dot = alignToPowerOf2(dot, isec->addralign); isec->outSecOff = dot - sec->addr; @@ -1423,114 +1364,6 @@ const Defined *LinkerScript::assignAddresses() { return getChangedSymbolAssignment(oldValues); } -static bool hasRegionOverflowed(MemoryRegion *mr) { - if (!mr) - return false; - return mr->curPos - mr->getOrigin() > mr->getLength(); -} - -// Spill input sections in reverse order of address assignment to (potentially) -// bring memory regions out of overflow. The size savings of a spill can only be -// estimated, since general linker script arithmetic may occur afterwards. -// Under-estimates may cause unnecessary spills, but over-estimates can always -// be corrected on the next pass. -bool LinkerScript::spillSections() { - if (!config->enableNonContiguousRegions) - return false; - - bool spilled = false; - for (SectionCommand *cmd : reverse(sectionCommands)) { - auto *od = dyn_cast<OutputDesc>(cmd); - if (!od) - continue; - OutputSection *osec = &od->osec; - if (!osec->memRegion) - continue; - - // Input sections that have replaced a potential spill and should be removed - // from their input section description. - DenseSet<InputSection *> spilledInputSections; - - for (SectionCommand *cmd : reverse(osec->commands)) { - if (!hasRegionOverflowed(osec->memRegion) && - !hasRegionOverflowed(osec->lmaRegion)) - break; - - auto *isd = dyn_cast<InputSectionDescription>(cmd); - if (!isd) - continue; - for (InputSection *isec : reverse(isd->sections)) { - // Potential spill locations cannot be spilled. - if (isa<PotentialSpillSection>(isec)) - continue; - - // Find the next potential spill location and remove it from the list. - auto it = potentialSpillLists.find(isec); - if (it == potentialSpillLists.end()) - continue; - PotentialSpillList &list = it->second; - PotentialSpillSection *spill = list.head; - if (spill->next) - list.head = spill->next; - else - potentialSpillLists.erase(isec); - - // Replace the next spill location with the spilled section and adjust - // its properties to match the new location. Note that the alignment of - // the spill section may have diverged from the original due to e.g. a - // SUBALIGN. Correct assignment requires the spill's alignment to be - // used, not the original. - spilledInputSections.insert(isec); - *llvm::find(spill->isd->sections, spill) = isec; - isec->parent = spill->parent; - isec->addralign = spill->addralign; - - // Record the (potential) reduction in the region's end position. - osec->memRegion->curPos -= isec->getSize(); - if (osec->lmaRegion) - osec->lmaRegion->curPos -= isec->getSize(); - - // Spilling continues until the end position no longer overflows the - // region. Then, another round of address assignment will either confirm - // the spill's success or lead to yet more spilling. - if (!hasRegionOverflowed(osec->memRegion) && - !hasRegionOverflowed(osec->lmaRegion)) - break; - } - - // Remove any spilled input sections to complete their move. - if (!spilledInputSections.empty()) { - spilled = true; - llvm::erase_if(isd->sections, [&](InputSection *isec) { - return spilledInputSections.contains(isec); - }); - } - } - } - - return spilled; -} - -// Erase any potential spill sections that were not used. -void LinkerScript::erasePotentialSpillSections() { - if (potentialSpillLists.empty()) - return; - - // Collect the set of input section descriptions that contain potential - // spills. - DenseSet<InputSectionDescription *> isds; - for (const auto &[_, list] : potentialSpillLists) - for (PotentialSpillSection *s = list.head; s; s = s->next) - isds.insert(s->isd); - - for (InputSectionDescription *isd : isds) - llvm::erase_if(isd->sections, [](InputSection *s) { - return isa<PotentialSpillSection>(s); - }); - - potentialSpillLists.clear(); -} - // Creates program headers as instructed by PHDRS linker script command. SmallVector<PhdrEntry *, 0> LinkerScript::createPhdrs() { SmallVector<PhdrEntry *, 0> ret; diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index 734d4e7..b09cd12 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -10,7 +10,6 @@ #define LLD_ELF_LINKER_SCRIPT_H #include "Config.h" -#include "InputSection.h" #include "Writer.h" #include "lld/Common/LLVM.h" #include "lld/Common/Strings.h" @@ -288,8 +287,7 @@ class LinkerScript final { SmallVector<InputSectionBase *, 0> computeInputSections(const InputSectionDescription *, - ArrayRef<InputSectionBase *>, - const OutputSection &outCmd); + ArrayRef<InputSectionBase *>); SmallVector<InputSectionBase *, 0> createInputSectionList(OutputSection &cmd); @@ -335,8 +333,6 @@ public: bool shouldKeep(InputSectionBase *s); const Defined *assignAddresses(); - bool spillSections(); - void erasePotentialSpillSections(); void allocateHeaders(SmallVector<PhdrEntry *, 0> &phdrs); void processSectionCommands(); void processSymbolAssignments(); @@ -404,15 +400,6 @@ public: // // then provideMap should contain the mapping: 'v' -> ['a', 'b', 'c'] llvm::MapVector<StringRef, SmallVector<StringRef, 0>> provideMap; - - // List of potential spill locations (PotentialSpillSection) for an input - // section. - struct PotentialSpillList { - // Never nullptr. - PotentialSpillSection *head; - PotentialSpillSection *tail; - }; - llvm::DenseMap<InputSectionBase *, PotentialSpillList> potentialSpillLists; }; struct ScriptWrapper { diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 883a607..b9e05a4 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -197,9 +197,6 @@ def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">; def enable_new_dtags: F<"enable-new-dtags">, HelpText<"Enable new dynamic tags (default)">; -def enable_non_contiguous_regions : FF<"enable-non-contiguous-regions">, - HelpText<"Spill input sections to later matching output sections to avoid memory region overflow">; - def end_group: F<"end-group">, HelpText<"Ignored for compatibility with GNU unless you pass --warn-backrefs">; diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index fcb4c43..9c66724 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -186,7 +186,7 @@ static MergeSyntheticSection *createMergeSynthetic(StringRef name, // 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(LinkerScript *script) { +void OutputSection::finalizeInputSections() { std::vector<MergeSyntheticSection *> mergeSections; for (SectionCommand *cmd : commands) { auto *isd = dyn_cast<InputSectionDescription>(cmd); @@ -226,11 +226,6 @@ void OutputSection::finalizeInputSections(LinkerScript *script) { i = std::prev(mergeSections.end()); syn->entsize = ms->entsize; isd->sections.push_back(syn); - // The merge synthetic section inherits the potential spill locations of - // its first contained section. - auto it = script->potentialSpillLists.find(ms); - if (it != script->potentialSpillLists.end()) - script->potentialSpillLists.try_emplace(syn, it->second); } (*i)->addSection(ms); } diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index 78fede4..421a018 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -75,7 +75,7 @@ public: void recordSection(InputSectionBase *isec); void commitSection(InputSection *isec); - void finalizeInputSections(LinkerScript *script = nullptr); + void finalizeInputSections(); // The following members are normally only used in linker scripts. MemoryRegion *memRegion = nullptr; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 298c714..7b9ada4 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -4074,13 +4074,6 @@ static bool isDuplicateArmExidxSec(InputSection *prev, InputSection *cur) { // InputSection with the highest address and any InputSections that have // mergeable .ARM.exidx table entries are removed from it. void ARMExidxSyntheticSection::finalizeContents() { - // Ensure that any fixed-point iterations after the first see the original set - // of sections. - if (!originalExecutableSections.empty()) - executableSections = originalExecutableSections; - else if (config->enableNonContiguousRegions) - originalExecutableSections = executableSections; - // The executableSections and exidxSections that we use to derive the final // contents of this SyntheticSection are populated before // processSectionCommands() and ICF. A /DISCARD/ entry in SECTIONS command or diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 34949025..995fd4b 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -1255,10 +1255,6 @@ private: // either find the .ARM.exidx section or know that we need to generate one. SmallVector<InputSection *, 0> executableSections; - // Value of executableSecitons before finalizeContents(), so that it can be - // run repeateadly during fixed point iteration. - SmallVector<InputSection *, 0> originalExecutableSections; - // The executable InputSection with the highest address to use for the // sentinel. We store separately from ExecutableSections as merging of // duplicate entries may mean this InputSection is removed from diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 8d529f2..e400ed2 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1403,18 +1403,13 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() { AArch64Err843419Patcher a64p; ARMErr657417Patcher a32p; script->assignAddresses(); - // .ARM.exidx and SHF_LINK_ORDER do not require precise addresses, but they // do require the relative addresses of OutputSections because linker scripts // can assign Virtual Addresses to OutputSections that are not monotonically - // increasing. Anything here must be repeatable, since spilling may change - // section order. - const auto finalizeOrderDependentContent = [this] { - for (Partition &part : partitions) - finalizeSynthetic(part.armExidx.get()); - resolveShfLinkOrder(); - }; - finalizeOrderDependentContent(); + // increasing. + for (Partition &part : partitions) + finalizeSynthetic(part.armExidx.get()); + resolveShfLinkOrder(); // Converts call x@GDPLT to call __tls_get_addr if (config->emachine == EM_HEXAGON) @@ -1424,8 +1419,6 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() { for (;;) { bool changed = target->needsThunks ? tc.createThunks(pass, outputSections) : target->relaxOnce(pass); - bool spilled = script->spillSections(); - changed |= spilled; ++pass; // With Thunk Size much smaller than branch range we expect to @@ -1471,9 +1464,6 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() { " does not converge"); break; } - } else if (spilled) { - // Spilling can change relative section order. - finalizeOrderDependentContent(); } } if (!config->relocatable) @@ -1493,10 +1483,6 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() { osec->name + " is not a multiple of alignment (" + Twine(osec->addralign) + ")"); } - - // Sizes are no longer allowed to grow, so all allowable spills have been - // taken. Remove any leftover potential spills. - script->erasePotentialSpillSections(); } // If Input Sections have been shrunk (basic block sections) then diff --git a/lld/docs/ELF/linker_script.rst b/lld/docs/ELF/linker_script.rst index 7a35534..3606ef4 100644 --- a/lld/docs/ELF/linker_script.rst +++ b/lld/docs/ELF/linker_script.rst @@ -197,14 +197,3 @@ the current location to a max-page-size boundary, ensuring that the next LLD will insert ``.relro_padding`` immediately before the symbol assignment using ``DATA_SEGMENT_RELRO_END``. - -Non-contiguous regions -~~~~~~~~~~~~~~~~~~~~~~ - -The flag ``--enable-non-contiguous-regions`` allows input sections to spill to -later matches rather than causing the link to fail by overflowing a memory -region. Unlike GNU ld, ``/DISCARD/`` only matches previously-unmatched sections -(i.e., the flag does not affect it). Also, if a section fails to fit at any of -its matches, the link fails instead of discarding the section. Accordingly, the -GNU flag ``--enable-non-contiguous-regions-warnings`` is not implemented, as it -exists to warn about such occurrences. diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst index e7a913e..f8fdebf 100644 --- a/lld/docs/ReleaseNotes.rst +++ b/lld/docs/ReleaseNotes.rst @@ -38,12 +38,6 @@ ELF Improvements * ``--debug-names`` is added to create a merged ``.debug_names`` index from input ``.debug_names`` sections. Type units are not handled yet. (`#86508 <https://github.com/llvm/llvm-project/pull/86508>`_) -* ``--enable-non-contiguous-regions`` option allows automatically packing input - sections into memory regions by automatically spilling to later matches if a - region would overflow. This reduces the toil of manually packing regions - (typical for embedded). It also makes full LTO feasible in such cases, since - IR merging currently prevents the linker script from referring to input - files. (`#90007 <https://github.com/llvm/llvm-project/pull/90007>`_) Breaking changes ---------------- diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1 index 0df13f0..9ea1a9c 100644 --- a/lld/docs/ld.lld.1 +++ b/lld/docs/ld.lld.1 @@ -222,8 +222,6 @@ segment header. Generate relocations in the output. .It Fl -enable-new-dtags Enable new dynamic tags. -.It Fl -enable-non-contiguous-regions -Spill input sections to later matching output sections to avoid memory region overflow. .It Fl -end-lib End a grouping of objects that should be treated as if they were together in an archive. diff --git a/lld/test/ELF/linkerscript/enable-non-contiguous-regions-arm-exidx.test b/lld/test/ELF/linkerscript/enable-non-contiguous-regions-arm-exidx.test deleted file mode 100644 index 3f7b9c4..0000000 --- a/lld/test/ELF/linkerscript/enable-non-contiguous-regions-arm-exidx.test +++ /dev/null @@ -1,55 +0,0 @@ -## When spilling reorders input sections, the .ARM.exidx table is rebuilt using -## the new order. - -# REQUIRES: arm -# RUN: rm -rf %t && split-file %s %t && cd %t -# RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi test.s -o test.o -# RUN: ld.lld -T test.ld test.o -o test --enable-non-contiguous-regions -# RUN: llvm-readobj -x .ARM.exidx test | FileCheck %s - -# CHECK: 20000000 08849780 1c000000 10849880 -# CHECK-NEXT: 1c000000 01000000 - -#--- test.ld -MEMORY { - exidx : ORIGIN = 0, LENGTH = 32 - a : ORIGIN = 32, LENGTH = 4 - b : ORIGIN = 36, LENGTH = 4 - c : ORIGIN = 40, LENGTH = 4 -} - -SECTIONS { - .ARM.exidx : { *(.ARM.exidx) } >exidx - .first_chance : { *(.text .text.f2) } >a - .text.f1 : { *(.text.f1) } >b - .last_chance : { *(.text.f2) } >c -} - -#--- test.s - .syntax unified - .section .text, "ax",%progbits - .globl _start -_start: - .fnstart - bx lr - .save {r7, lr} - .setfp r7, sp, #0 - .fnend - - .section .text.f1, "ax", %progbits - .globl f1 -f1: - .fnstart - bx lr - .save {r8, lr} - .setfp r8, sp, #0 - .fnend - - .section .text.f2, "ax", %progbits - .globl f2 -f2: - .fnstart - bx lr - .save {r8, lr} - .setfp r8, sp, #0 - .fnend diff --git a/lld/test/ELF/linkerscript/enable-non-contiguous-regions.test b/lld/test/ELF/linkerscript/enable-non-contiguous-regions.test deleted file mode 100644 index 392106f..0000000 --- a/lld/test/ELF/linkerscript/enable-non-contiguous-regions.test +++ /dev/null @@ -1,265 +0,0 @@ -# REQUIRES: x86 - -# RUN: rm -rf %t && split-file %s %t && cd %t -# RUN: llvm-mc -n -filetype=obj -triple=x86_64 spill.s -o spill.o - -## An input section spills to a later match when the region of its first match -## would overflow. The spill uses the alignment of the later match. - -# RUN: ld.lld -T spill.ld spill.o -o spill --enable-non-contiguous-regions -# RUN: llvm-readelf -S spill | FileCheck %s --check-prefix=SPILL - -# SPILL: Name Type Address Off Size -# SPILL: .first_chance PROGBITS 0000000000000000 001000 000001 -# SPILL-NEXT: .last_chance PROGBITS 0000000000000008 001008 000002 - -## A spill off the end still fails the link. - -# RUN: not ld.lld -T spill-fail.ld spill.o --enable-non-contiguous-regions 2>&1 |\ -# RUN: FileCheck %s --check-prefix=SPILL-FAIL --implicit-check-not=error: - -# SPILL-FAIL: error: section '.last_chance' will not fit in region 'b': overflowed by 2 bytes - -## The above spill still occurs when the LMA would overflow, even though the -## VMA would fit. - -# RUN: ld.lld -T spill-lma.ld spill.o -o spill-lma --enable-non-contiguous-regions -# RUN: llvm-readelf -S spill-lma | FileCheck %s --check-prefix=SPILL-LMA - -# SPILL-LMA: Name Type Address Off Size -# SPILL-LMA: .first_chance PROGBITS 0000000000000000 001000 000001 -# SPILL-LMA-NEXT: .last_chance PROGBITS 0000000000000003 001003 000002 - -## A spill occurs to an additional match after the first. - -# RUN: ld.lld -T spill-later.ld spill.o -o spill-later --enable-non-contiguous-regions -# RUN: llvm-readelf -S spill-later | FileCheck %s --check-prefix=SPILL-LATER - -# SPILL-LATER: Name Type Address Off Size -# SPILL-LATER: .first_chance PROGBITS 0000000000000000 001000 000001 -# SPILL-LATER-NEXT: .second_chance PROGBITS 0000000000000002 001001 000000 -# SPILL-LATER-NEXT: .last_chance PROGBITS 0000000000000003 001003 000002 - -## A later overflow causes an earlier section to spill. - -# RUN: ld.lld -T spill-earlier.ld spill.o -o spill-earlier --enable-non-contiguous-regions -# RUN: llvm-readelf -S spill-earlier | FileCheck %s --check-prefix=SPILL-EARLIER - -# SPILL-EARLIER: Name Type Address Off Size -# SPILL-EARLIER: .first_chance PROGBITS 0000000000000000 001000 000002 -# SPILL-EARLIER-NEXT: .last_chance PROGBITS 0000000000000002 001002 000001 - -## An additional match in /DISCARD/ has no effect. - -# RUN: not ld.lld -T no-spill-into-discard.ld spill.o --enable-non-contiguous-regions 2>&1 |\ -# RUN: FileCheck %s --check-prefix=NO-SPILL-INTO-DISCARD --implicit-check-not=error: - -# NO-SPILL-INTO-DISCARD: error: section '.osec' will not fit in region 'a': overflowed by 1 bytes - -## An additional match after /DISCARD/ has no effect. - -# RUN: ld.lld -T no-spill-from-discard.ld spill.o -o no-spill-from-discard --enable-non-contiguous-regions -# RUN: llvm-readelf -S no-spill-from-discard | FileCheck %s --check-prefix=NO-SPILL-FROM-DISCARD - -# NO-SPILL-FROM-DISCARD: Name Type Address Off Size -# NO-SPILL-FROM-DISCARD-NOT: .osec - -## SHF_MERGEd sections are spilled according to the matches of the first merged -## input section (the one giving the resulting section its name). - -# RUN: llvm-mc -n -filetype=obj -triple=x86_64 merge.s -o merge.o -# RUN: ld.lld -T spill-merge.ld merge.o -o spill-merge --enable-non-contiguous-regions -# RUN: llvm-readelf -S spill-merge | FileCheck %s --check-prefix=SPILL-MERGE - -# SPILL-MERGE: Name Type Address Off Size -# SPILL-MERGE: .first PROGBITS 0000000000000000 000190 000000 -# SPILL-MERGE-NEXT: .second PROGBITS 0000000000000001 001001 000002 -# SPILL-MERGE-NEXT: .third PROGBITS 0000000000000003 001003 000000 - -## An error is reported for INSERT. - -# RUN: not ld.lld -T insert.ld spill.o --enable-non-contiguous-regions 2>&1 |\ -# RUN: FileCheck %s --check-prefix=INSERT - -# INSERT: error: INSERT cannot be used with --enable-non-contiguous-regions - -## An error is reported for OVERWRITE_SECTIONS. - -# RUN: not ld.lld -T overwrite-sections.ld spill.o --enable-non-contiguous-regions 2>&1 |\ -# RUN: FileCheck %s --check-prefix=OVERWRITE_SECTIONS - -# OVERWRITE_SECTIONS: error: OVERWRITE_SECTIONS cannot be used with --enable-non-contiguous-regions - -## SHF_LINK_ORDER is reordered when spilling changes relative section order. - -# RUN: llvm-mc -n -filetype=obj -triple=x86_64 link-order.s -o link-order.o -# RUN: ld.lld -T link-order.ld link-order.o -o link-order --enable-non-contiguous-regions -# RUN: llvm-readobj -x .order link-order | FileCheck %s --check-prefix=LINK-ORDER - -# LINK-ORDER: 020301 - -#--- spill.s -.section .one_byte_section,"a",@progbits -.fill 1 - -.section .two_byte_section,"a",@progbits -.fill 2 - -#--- spill.ld -MEMORY { - a : ORIGIN = 0, LENGTH = 2 - b : ORIGIN = 2, LENGTH = 16 -} - -SECTIONS { - .first_chance : SUBALIGN(1) { *(.one_byte_section) *(.two_byte_section) } >a - .last_chance : SUBALIGN(8) { *(.two_byte_section) } >b -} - -#--- spill-fail.ld -MEMORY { - a : ORIGIN = 0, LENGTH = 1 - b : ORIGIN = 2, LENGTH = 0 -} - -SECTIONS { - .first_chance : { *(.one_byte_section) *(.two_byte_section) } >a - .last_chance : { *(.two_byte_section) } >b -} - -#--- spill-lma.ld -MEMORY { - vma_a : ORIGIN = 0, LENGTH = 3 - vma_b : ORIGIN = 3, LENGTH = 3 - lma_a : ORIGIN = 6, LENGTH = 2 - lma_b : ORIGIN = 8, LENGTH = 2 -} - -SECTIONS { - .first_chance : { *(.one_byte_section) *(.two_byte_section) } >vma_a AT>lma_a - .last_chance : { *(.two_byte_section) } >vma_b AT>lma_b -} - -#--- spill-later.ld -MEMORY { - a : ORIGIN = 0, LENGTH = 2 - b : ORIGIN = 2, LENGTH = 1 - c : ORIGIN = 3, LENGTH = 2 -} - -SECTIONS { - .first_chance : { *(.one_byte_section) *(.two_byte_section) } >a - .second_chance : { *(.two_byte_section) } >b - .last_chance : { *(.two_byte_section) } >c -} - -#--- spill-earlier.ld -MEMORY { - a : ORIGIN = 0, LENGTH = 2 - b : ORIGIN = 2, LENGTH = 1 -} - -SECTIONS { - .first_chance : { *(.one_byte_section) *(.two_byte_section) } >a - .last_chance : { *(.one_byte_section) } >b -} - -#--- no-spill-into-discard.ld -MEMORY { - a : ORIGIN = 0, LENGTH = 1 -} - -SECTIONS { - .osec : { *(.two_byte_section) } >a - /DISCARD/ : { *(.one_byte_section) *(.two_byte_section) } -} - -#--- no-spill-from-discard.ld -MEMORY { - a : ORIGIN = 0, LENGTH = 2 -} - -SECTIONS { - /DISCARD/ : { *(.one_byte_section) *(.two_byte_section) } - .osec : { *(.two_byte_section) } >a -} - -#--- merge.s -.section .a,"aM",@progbits,1 -.byte 0x12, 0x34 - -.section .b,"aM",@progbits,1 -.byte 0x12 - -#--- spill-merge.ld -MEMORY { - a : ORIGIN = 0, LENGTH = 1 - b : ORIGIN = 1, LENGTH = 2 - c : ORIGIN = 3, LENGTH = 2 -} - -SECTIONS { - .first : { *(.a) *(.b) } >a - .second : { *(.a) } >b - .third : { *(.b) } >c -} - -#--- insert.ld -MEMORY { - a : ORIGIN = 0, LENGTH = 1 -} - -SECTIONS { - .a : { *(.two_byte_section) } >a -} - -SECTIONS { - .b : { *(.one_byte_section) } >a -} INSERT AFTER .a; - -#--- overwrite-sections.ld -MEMORY { - a : ORIGIN = 0, LENGTH = 1 -} - -SECTIONS { - .a : { *(.two_byte_section) } >a -} - -OVERWRITE_SECTIONS { - .b : { *(.one_byte_section) } >a -} - -#--- link-order.s -.section .a,"a",@progbits -.fill 1 - -.section .b,"a",@progbits -.fill 1 - -.section .c,"a",@progbits -.fill 1 - -.section .link_order.a,"ao",@progbits,.a -.byte 1 - -.section .link_order.b,"ao",@progbits,.b -.byte 2 - -.section .link_order.c,"ao",@progbits,.c -.byte 3 - -#--- link-order.ld -MEMORY { - order : ORIGIN = 0, LENGTH = 3 - potential_a : ORIGIN = 3, LENGTH = 0 - bc : ORIGIN = 3, LENGTH = 2 - actual_a : ORIGIN = 5, LENGTH = 1 -} - -SECTIONS { - .order : { *(.link_order.*) } > order - .potential_a : { *(.a) } >potential_a - .bc : { *(.b) *(.c) } >bc - .actual_a : { *(.a) } >actual_a -} |