Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -228,7 +228,6 @@ MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd); void switchTo(OutputSection *Sec); - void flush(); void output(InputSection *Sec); void process(BaseCommand &Base); @@ -242,9 +241,6 @@ OutputSection *CurOutSec = nullptr; MemoryRegion *CurMemRegion = nullptr; - llvm::DenseSet AlreadyOutputOS; - llvm::DenseSet AlreadyOutputIS; - public: bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); } uint64_t getDot() { return Dot; } @@ -271,6 +267,7 @@ void assignOffsets(OutputSectionCommand *Cmd); void placeOrphanSections(); void processNonSectionCommands(); + void synchronize(); void assignAddresses(std::vector &Phdrs); int getSectionIndex(StringRef Name); Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -475,10 +475,15 @@ 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(*I)->Sec); + } else { + auto *Cmd = cast(*I); + Factory.addInputSec(S, Name, Cmd->Sec); + auto *ISD = make(""); + ISD->Sections.push_back(S); + Cmd->Commands.push_back(ISD); + } } } @@ -487,8 +492,6 @@ } 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 @@ 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 @@ if (!Sec->Live) continue; - assert(CurOutSec == Sec->OutSec || AlreadyOutputOS.count(Sec->OutSec)); + assert(CurOutSec == Sec->OutSec); output(cast(Sec)); } } @@ -642,19 +635,8 @@ 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(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 *Cmd : Cmd->Commands) + process(*Cmd); } void LinkerScript::removeEmptyCommands() { @@ -830,9 +812,15 @@ }); if (Pos == E) { auto *Cmd = make(Name); - Cmd->Sec = Sec; Opt.Commands.insert(CmdIter, Cmd); ++CmdIndex; + + Cmd->Sec = Sec; + auto *ISD = make(""); + for (InputSection *IS : Sec->Sections) + ISD->Sections.push_back(IS); + Cmd->Commands.push_back(ISD); + continue; } @@ -850,6 +838,49 @@ } } +// 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(Base); + if (!Cmd) + continue; + ArrayRef Sections = Cmd->Sec->Sections; + std::vector ScriptSections; + for (BaseCommand *Base : Cmd->Commands) { + auto *ISD = dyn_cast(Base); + if (!ISD) + continue; + for (InputSectionBase *&IS : ISD->Sections) + if (IS->Live) + ScriptSections.push_back(&IS); + } + std::vector 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(""); + 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 &Phdrs) { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -254,6 +254,7 @@ 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 @@ 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())