diff options
-rw-r--r-- | lld/ELF/LinkerScript.cpp | 96 | ||||
-rw-r--r-- | lld/ELF/LinkerScript.h | 5 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 2 |
3 files changed, 69 insertions, 34 deletions
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 74b5aa0f1fc..f7bc2370ba4 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -475,10 +475,15 @@ void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { return Cmd->Name == Name; return false; }); - if (I == Opt.Commands.end()) + if (I == Opt.Commands.end()) { Factory.addInputSec(S, Name); - else - Factory.addInputSec(S, Name, cast<OutputSectionCommand>(*I)->Sec); + } else { + auto *Cmd = cast<OutputSectionCommand>(*I); + Factory.addInputSec(S, Name, Cmd->Sec); + auto *ISD = make<InputSectionDescription>(""); + ISD->Sections.push_back(S); + Cmd->Commands.push_back(ISD); + } } } @@ -487,8 +492,6 @@ static bool isTbss(OutputSection *Sec) { } void LinkerScript::output(InputSection *S) { - if (!AlreadyOutputIS.insert(S).second) - return; bool IsTbss = isTbss(CurOutSec); uint64_t Pos = IsTbss ? Dot + ThreadBssOffset : Dot; @@ -520,19 +523,9 @@ void LinkerScript::output(InputSection *S) { Dot = Pos; } -void LinkerScript::flush() { - assert(CurOutSec); - if (!AlreadyOutputOS.insert(CurOutSec).second) - return; - for (InputSection *I : CurOutSec->Sections) - output(I); -} - void LinkerScript::switchTo(OutputSection *Sec) { if (CurOutSec == Sec) return; - if (AlreadyOutputOS.count(Sec)) - return; CurOutSec = Sec; @@ -583,7 +576,7 @@ void LinkerScript::process(BaseCommand &Base) { if (!Sec->Live) continue; - assert(CurOutSec == Sec->OutSec || AlreadyOutputOS.count(Sec->OutSec)); + assert(CurOutSec == Sec->OutSec); output(cast<InputSection>(Sec)); } } @@ -642,19 +635,8 @@ void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { Dot = CurMemRegion->Offset; switchTo(Sec); - // flush() may add orphan sections, so the order of flush() and - // symbol assignments is important. We want to call flush() first so - // that symbols pointing the end of the current section points to - // the location after orphan sections. - auto Mid = - std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(), - [](BaseCommand *Cmd) { return !isa<SymbolAssignment>(Cmd); }) - .base(); - for (auto I = Cmd->Commands.begin(); I != Mid; ++I) - process(**I); - flush(); - for (auto I = Mid, E = Cmd->Commands.end(); I != E; ++I) - process(**I); + for (BaseCommand *C : Cmd->Commands) + process(*C); } void LinkerScript::removeEmptyCommands() { @@ -824,15 +806,24 @@ void LinkerScript::placeOrphanSections() { ++CmdIndex; } + // If there is no command corresponding to this output section, + // create one and put a InputSectionDescription in it so that both + // representations agree on which input sections to use. auto Pos = std::find_if(CmdIter, E, [&](BaseCommand *Base) { auto *Cmd = dyn_cast<OutputSectionCommand>(Base); return Cmd && Cmd->Name == Name; }); if (Pos == E) { auto *Cmd = make<OutputSectionCommand>(Name); - Cmd->Sec = Sec; Opt.Commands.insert(CmdIter, Cmd); ++CmdIndex; + + Cmd->Sec = Sec; + auto *ISD = make<InputSectionDescription>(""); + for (InputSection *IS : Sec->Sections) + ISD->Sections.push_back(IS); + Cmd->Commands.push_back(ISD); + continue; } @@ -850,6 +841,51 @@ void LinkerScript::processNonSectionCommands() { } } +// Do a last effort at synchronizing the linker script "AST" and the section +// list. This is needed to account for last minute changes, like adding a +// .ARM.exidx terminator and sorting SHF_LINK_ORDER sections. +// +// FIXME: We should instead create the "AST" earlier and the above changes would +// be done directly in the "AST". +// +// This can only handle new sections being added and sections being reordered. +void LinkerScript::synchronize() { + for (BaseCommand *Base : Opt.Commands) { + auto *Cmd = dyn_cast<OutputSectionCommand>(Base); + if (!Cmd) + continue; + ArrayRef<InputSection *> Sections = Cmd->Sec->Sections; + std::vector<InputSectionBase **> ScriptSections; + DenseSet<InputSectionBase *> ScriptSectionsSet; + for (BaseCommand *Base : Cmd->Commands) { + auto *ISD = dyn_cast<InputSectionDescription>(Base); + if (!ISD) + continue; + for (InputSectionBase *&IS : ISD->Sections) { + if (IS->Live) { + ScriptSections.push_back(&IS); + ScriptSectionsSet.insert(IS); + } + } + } + std::vector<InputSectionBase *> Missing; + for (InputSection *IS : Sections) + if (!ScriptSectionsSet.count(IS)) + Missing.push_back(IS); + if (!Missing.empty()) { + auto ISD = make<InputSectionDescription>(""); + ISD->Sections = Missing; + Cmd->Commands.push_back(ISD); + for (InputSectionBase *&IS : ISD->Sections) + if (IS->Live) + ScriptSections.push_back(&IS); + } + assert(ScriptSections.size() == Sections.size()); + for (int I = 0, N = Sections.size(); I < N; ++I) + *ScriptSections[I] = Sections[I]; + } +} + void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index 61942b2db35..dd96d335a66 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -228,7 +228,6 @@ protected: MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd); void switchTo(OutputSection *Sec); - void flush(); void output(InputSection *Sec); void process(BaseCommand &Base); @@ -242,9 +241,6 @@ protected: OutputSection *CurOutSec = nullptr; MemoryRegion *CurMemRegion = nullptr; - llvm::DenseSet<OutputSection *> AlreadyOutputOS; - llvm::DenseSet<InputSectionBase *> AlreadyOutputIS; - public: bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); } uint64_t getDot() { return Dot; } @@ -271,6 +267,7 @@ public: void assignOffsets(OutputSectionCommand *Cmd); void placeOrphanSections(); void processNonSectionCommands(); + void synchronize(); void assignAddresses(std::vector<PhdrEntry> &Phdrs); int getSectionIndex(StringRef Name); diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index f4d41ebfa78..e2ab48433a5 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -254,6 +254,7 @@ template <class ELFT> void Writer<ELFT>::run() { fixSectionAlignments(); Script->fabricateDefaultCommands(Config->MaxPageSize); } + Script->synchronize(); Script->assignAddresses(Phdrs); // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a @@ -1080,6 +1081,7 @@ static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) { SS->OutSec->Sections.erase(std::find(SS->OutSec->Sections.begin(), SS->OutSec->Sections.end(), SS)); + SS->Live = false; // If there are no other sections in the output section, remove it from the // output. if (SS->OutSec->Sections.empty()) |