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 @@ -88,11 +88,7 @@ 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++; // If this section contains a table of fixed-size entries, sh_entsize // holds the element size. Consequently, if this contains two or more @@ -335,6 +331,12 @@ !Name.startswith(".debug_")) return; + // Calculate the section offsets and size pre-compression. + for (BaseCommand * Cmd : Commands) + if (auto *ISD = dyn_cast(Cmd)) + for (InputSection *IS : ISD->Sections) + Size = updateOffset(Size, IS); + // Create a section header. ZDebugHeader.resize(sizeof(Elf_Chdr)); auto *Hdr = reinterpret_cast(ZDebugHeader.data()); @@ -427,7 +429,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 @@ -821,6 +821,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) { @@ -831,7 +843,13 @@ // 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 will be accurate as long as users don't modify the + // section size via the linker script. If they do use a custom layout + // using linker scripts, then the size may be lower than necessary, + // resulting in fewer GOT entries than are potentially needed. + 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