Index: ELF/ICF.cpp =================================================================== --- ELF/ICF.cpp +++ ELF/ICF.cpp @@ -303,10 +303,10 @@ a->getSize() != b->getSize() || a->data() != b->data()) return false; - // If two sections have different output sections, we cannot merge them. - // FIXME: This doesn't do the right thing in the case where there is a linker - // script. We probably need to move output section assignment before ICF to - // get the correct behaviour here. + // If two sections have different output sections, we cannot merge them. When + // there is a linker script, getOutputSectionName may be inaccurate, sections + // going into different output sections may get folded but they will be + // unfolded in LinkerScript::processSectionCommands. if (getOutputSectionName(a) != getOutputSectionName(b)) return false; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -378,7 +378,7 @@ size_t sizeBefore = ret.size(); for (InputSectionBase *sec : inputSections) { - if (!sec->isLive() || sec->assigned) + if (sec->assigned || (!sec->isLive() && sec->repl == sec)) continue; // For -emit-relocs we have to ignore entries like @@ -421,8 +421,11 @@ if (s == mainPart->hashTab) mainPart->hashTab = nullptr; - s->assigned = false; + // Entirely discarded. s->repl != s indicates a section that can be unfolded + // later. s->markDead(); + s->repl = s; + discard(s->dependentSections); } } @@ -461,6 +464,7 @@ ctx = deleter.get(); ctx->outSec = aether; + DenseMap> inputs; size_t i = 0; // Add input sections to output sections. for (BaseCommand *base : sectionCommands) { @@ -510,9 +514,9 @@ s->alignment = subalign; } - // Add input sections to an output section. - for (InputSection *s : v) - sec->addSection(s); + for (InputSection *&s : v) + s->parent = sec; + inputs[sec] = std::move(v); sec->sectionIndex = i++; if (sec->noload) @@ -521,6 +525,28 @@ sec->flags &= ~(uint64_t)SHF_ALLOC; } } + + // Do not ICF fold input sections between output sections. If the output + // sections of sec and the InputSection it gets folded into are different, + // unfold it. sec->repl may have increased alignment or be have moved to the + // main partition, but that does not matter. + for (auto &it : inputs) + for (InputSection *s : it.second) + if (s->repl != s && cast(s->repl)->getParent() != s->getParent()) { + s->repl = s; + s->markLive(); + for (InputSection *dependent : s->dependentSections) + dependent->markLive(); + } + + // Delete garbage-collected or folded input sections. + for (auto &it : inputs) { + OutputSection *sec = it.first; + for (InputSection *&s : it.second) + if (s->isLive()) + sec->addSection(s); + } + ctx = nullptr; }