Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -314,6 +314,10 @@ // to. The writer sets a value. uint64_t OutSecOff = 0; + // The order in which the section was added to its output section. This is + // used when ordering SHF_LINK_ORDER sections. + size_t OutSecPos = 0; + static bool classof(const SectionBase *S); InputSectionBase *getRelocatedSection(); Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -113,6 +113,10 @@ void sort(std::function Order); void sortInitFini(); void sortCtorsDtors(); + +private: + // The number of input sections assigned to this section. + size_t InputSectionCount = 0; }; int getPriority(StringRef S); Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -82,17 +82,23 @@ return Off + S->getSize(); } +static bool shouldCompress(uint64_t Flags, StringRef SectionName) { + return Config->CompressDebugSections && !(Flags & SHF_ALLOC) && + SectionName.startswith(".debug_"); +} + void OutputSection::addSection(InputSection *S) { assert(S->Live); Live = true; S->Parent = this; this->updateAlignment(S->Alignment); - // The actual offsets will be computed by assignAddresses. For now, use - // crude approximation so that it is at least easy for other code to know the - // section order. It is also used to calculate the output section size early - // for compressed debug sections. - this->Size = updateOffset(Size, S); + S->OutSecPos = InputSectionCount++; + + // The offset and size needs to be calculated early for compressed debug + // sections. + if (shouldCompress(Flags, Name)) + Size = updateOffset(Size, S); // If this section contains a table of fixed-size entries, sh_entsize // holds the element size. Consequently, if this contains two or more @@ -331,8 +337,7 @@ typedef typename ELFT::Chdr Elf_Chdr; // Compress only DWARF debug sections. - if (!Config->CompressDebugSections || (Flags & SHF_ALLOC) || - !Name.startswith(".debug_")) + if (!shouldCompress(Flags, Name)) return; // Create a section header. @@ -427,7 +432,7 @@ OutputSection *BOut = LB->getParent(); if (AOut != BOut) return AOut->SectionIndex < BOut->SectionIndex; - return LA->OutSecOff < LB->OutSecOff; + return LA->OutSecPos < LB->OutSecPos; } template Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -819,6 +819,18 @@ void MipsGotSection::finalizeContents() { updateAllocSize(); } +static uint64_t estimateOutputSectionSize(const OutputSection *OS) { + uint64_t Size = 0; + for (BaseCommand *Cmd : OS->Commands) { + if (auto *ISD = cast(Cmd)) { + for (InputSection *IS : ISD->Sections) { + Size = alignTo(Size, IS->Alignment) + IS->getSize(); + } + } + } + return Size; +} + void MipsGotSection::updateAllocSize() { PageEntriesNum = 0; for (std::pair &P : PageIndexMap) { @@ -829,7 +841,11 @@ // against it. And take in account the case when the section intersects // page boundaries. P.second = PageEntriesNum; - PageEntriesNum += getMipsPageCount(P.first->Size); + // The OutputSection Size is not set until after assignAddresses has been + // called, so we cannot use it. Instead we make a rough estimate of the + // section size, which should be sufficient as long as users don't start + // modifying the section size via the linker script. + PageEntriesNum += getMipsPageCount(estimateOutputSectionSize(P.first)); } Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) * Config->Wordsize; Index: test/ELF/linkerscript/unused-synthetic.s =================================================================== --- test/ELF/linkerscript/unused-synthetic.s +++ test/ELF/linkerscript/unused-synthetic.s @@ -13,6 +13,16 @@ # CHECK: .text # CHECK-NEXT: .dynsym +# Test that the size of a removed unused synthetic input section does not get +# added to the output section size, if the output section has symbol +# assignments, preventing removal of the output section. +# RUN: echo "SECTIONS { \ +# RUN: .got.plt : { a_sym = .; *(.got.plt) } \ +# RUN: }" > %t2.script +# RUN: ld.lld -shared -o %t2.so --script %t2.script %t.o +# RUN: llvm-objdump -section-headers %t2.so | FileCheck %s --check-prefix=CHECK2 +# CHECK2: .got.plt 00000000 + .global _start _start: nop