diff options
-rw-r--r-- | lld/ELF/LinkerScript.cpp | 94 | ||||
-rw-r--r-- | lld/ELF/LinkerScript.h | 5 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 2 |
3 files changed, 34 insertions, 67 deletions
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index be6a0ca9027..74b5aa0f1fc 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -475,15 +475,10 @@ 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 { - 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); - } + else + Factory.addInputSec(S, Name, cast<OutputSectionCommand>(*I)->Sec); } } @@ -492,6 +487,8 @@ 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; @@ -523,9 +520,19 @@ 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; @@ -576,7 +583,7 @@ void LinkerScript::process(BaseCommand &Base) { if (!Sec->Live) continue; - assert(CurOutSec == Sec->OutSec); + assert(CurOutSec == Sec->OutSec || AlreadyOutputOS.count(Sec->OutSec)); output(cast<InputSection>(Sec)); } } @@ -635,8 +642,19 @@ void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { Dot = CurMemRegion->Offset; switchTo(Sec); - for (BaseCommand *C : Cmd->Commands) - process(*C); + // 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); } void LinkerScript::removeEmptyCommands() { @@ -806,24 +824,15 @@ 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; } @@ -841,49 +850,6 @@ 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; - 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); - } - std::vector<InputSectionBase *> Missing; - for (InputSection *IS : Sections) - if (std::find_if(ScriptSections.begin(), ScriptSections.end(), - [=](InputSectionBase **Base) { return *Base == IS; }) == - ScriptSections.end()) - 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 dd96d335a66..61942b2db35 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -228,6 +228,7 @@ protected: MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd); void switchTo(OutputSection *Sec); + void flush(); void output(InputSection *Sec); void process(BaseCommand &Base); @@ -241,6 +242,9 @@ 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; } @@ -267,7 +271,6 @@ 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 e2ab48433a5..f4d41ebfa78 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -254,7 +254,6 @@ 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 @@ -1081,7 +1080,6 @@ 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()) |