Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -314,6 +314,11 @@ // 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. It is not set for sections + // inserted late, such as thunk sections. + llvm::Optional OutSecPos; + static bool classof(const SectionBase *S); InputSectionBase *getRelocatedSection(); Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -113,6 +113,11 @@ void sort(std::function Order); void sortInitFini(); void sortCtorsDtors(); + +private: + // The number of input sections assigned to this section excluding + // late-inserted sections, such as thunk sections. + size_t InputSectionCount = 0; }; int getPriority(StringRef S); Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -87,12 +87,7 @@ 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++; // 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 +330,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 +428,9 @@ OutputSection *BOut = LB->getParent(); if (AOut != BOut) return AOut->SectionIndex < BOut->SectionIndex; - return LA->OutSecOff < LB->OutSecOff; + assert(LA->OutSecPos && LB->OutSecPos && + "Cannot compare late-inserted section positions."); + return LA->OutSecPos < LB->OutSecPos; } template Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -172,7 +172,6 @@ void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } void updateAllocSize() override; - void finalizeContents() override; bool empty() const override; void addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr); bool addDynTlsEntry(SymbolBody &Sym); @@ -367,6 +366,7 @@ public: DynamicSection(); void finalizeContents() override; + void postThunkContents() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -819,8 +819,6 @@ LocalEntries32.size(); } -void MipsGotSection::finalizeContents() { updateAllocSize(); } - void MipsGotSection::updateAllocSize() { PageEntriesNum = 0; for (std::pair &P : PageIndexMap) { @@ -1161,7 +1159,9 @@ add({DT_MIPS_FLAGS, RHF_NOTPOT}); add({DT_MIPS_BASE_ADDRESS, Config->ImageBase}); add({DT_MIPS_SYMTABNO, InX::DynSymTab->getNumSymbols()}); - add({DT_MIPS_LOCAL_GOTNO, InX::MipsGot->getLocalEntriesNum()}); + // The number of local got entries has not yet been determined. This value + // will be updated in postThunkContents(). + add({DT_MIPS_LOCAL_GOTNO, uint64_t(0)}); if (const SymbolBody *B = InX::MipsGot->getFirstGlobalEntry()) add({DT_MIPS_GOTSYM, B->DynsymIndex}); else @@ -1177,6 +1177,18 @@ this->Size = (Entries.size() + 1) * this->Entsize; } +template void DynamicSection::postThunkContents() { + if (!InX::MipsGot) + return; + + for (Entry &E : Entries) { + if (E.Tag == DT_MIPS_LOCAL_GOTNO) { + E.Val = InX::MipsGot->getLocalEntriesNum(); + return; + } + } +} + template void DynamicSection::writeTo(uint8_t *Buf) { auto *P = reinterpret_cast(Buf); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1367,16 +1367,23 @@ // jump instructions if jump targets are too far. Create thunks. if (Target->NeedsThunks) { // FIXME: only ARM Interworking and Mips LA25 Thunks are implemented, - // these - // do not require address information. To support range extension Thunks - // we need to assign addresses so that we can tell if jump instructions - // are out of range. This will need to turn into a loop that converges - // when no more Thunks are added + // these do not require address information. To support range extension + // Thunks we need to assign addresses so that we can tell if jump + // instructions are out of range. This will need to turn into a loop that + // converges when no more Thunks are added. ThunkCreator TC; Script->assignAddresses(); + applySynthetic({InX::MipsGot}, + [](SyntheticSection *SS) { SS->updateAllocSize(); }); if (TC.createThunks(OutputSections)) { - applySynthetic({InX::MipsGot}, - [](SyntheticSection *SS) { SS->updateAllocSize(); }); + applySynthetic({InX::MipsGot}, [](SyntheticSection *SS) { + // Adding thunks might have affected the output section sizes. We need + // to update them before updating the MIPS GOT size once more, as it + // might now need more entries than before. assignAddresses() does this + // job. + Script->assignAddresses(); + SS->updateAllocSize(); + }); if (TC.createThunks(OutputSections)) fatal("All non-range thunks should be created in first call"); } @@ -1388,8 +1395,10 @@ for (OutputSection *Sec : OutputSections) Sec->finalize(); - // createThunks may have added local symbols to the static symbol table - applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab}, + // createThunks may have added local symbols to the static symbol table. + // The value of the DT_MIPS_LOCAL_GOTNO entry also needs setting now that the + // number of entries has been determined. + applySynthetic({InX::SymTab, InX::Dynamic}, [](SyntheticSection *SS) { SS->postThunkContents(); }); } 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