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); } } @@ -521,6 +524,28 @@ sec->flags &= ~(uint64_t)SHF_ALLOC; } } + + for (BaseCommand *base : script->sectionCommands) + if (auto *sec = dyn_cast(base)) + for (BaseCommand *sub_base : sec->sectionCommands) + if (auto *isd = dyn_cast(sub_base)) { + // 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 (InputSection *s : isd->sections) + if (s->repl != s && + cast(s->repl)->getParent() != s->getParent()) { + s->repl = s; + s->markLive(); + for (InputSection *dependent : s->dependentSections) + dependent->markLive(); + } + + llvm::erase_if(isd->sections, + [](InputSection *isec) { return !isec->isLive(); }); + } + ctx = nullptr; }