Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -13,6 +13,7 @@ #include "Config.h" #include "lld/Core/LLVM.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELF.h" @@ -124,6 +125,8 @@ std::vector Entries; uint32_t TlsIndexOff = -1; uint32_t MipsLocalEntries = 0; + // Output sections referenced by MIPS GOT relocations. + llvm::SmallPtrSet *, 10> MipsOutSections; llvm::DenseMap MipsLocalGotPos; uintX_t getMipsLocalEntryAddr(uintX_t EntryValue); Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -115,16 +115,30 @@ // // See "Global Offset Table" in Chapter 5: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - // - // FIXME (simon): Now LLD allocates GOT entries for each - // "local symbol+addend" pair. That should be fixed to reduce size - // of generated GOT. - if (Sym.isPreemptible()) - Sym.MustBeInDynSym = true; - else { + if (Sym.isLocal()) { + // At this point we do not know final symbol value so to reduce number + // of allocated GOT entries do the following trick. Save all output + // sections referenced by GOT relocations. Then later in the `finalize` + // method calculate number of "pages" required to cover all saved output + // section and allocate appropriate number of GOT entries. + auto *OutSec = cast>(&Sym)->Section->OutSec; + MipsOutSections.insert(OutSec); + return; + } + if (!Sym.isPreemptible()) { + // In case of non-local symbols require an entry in the local part + // of MIPS GOT, we set GotIndex to 1 just to accent that this symbol + // has the GOT entry and escape creation more redundant GOT entries. + // FIXME (simon): We can try to store such symbols in the `Entries` + // container. But in that case we have to sort out that container + // and update GotIndex assigned to symbols. + Sym.GotIndex = 1; ++MipsLocalEntries; return; } + // All preemptible symbols with MIPS GOT entries should be represented + // in the dynamic symbols table. + Sym.MustBeInDynSym = true; } Sym.GotIndex = Entries.size(); Entries.push_back(&Sym); @@ -191,6 +205,15 @@ } template void GotSection::finalize() { + for (const OutputSectionBase *OutSec : MipsOutSections) { + // Calculate number of MIPS GOT entries required to store page + // addresses of local symbols. We assume that symbols referenced + // by GOT relocations are spread uniformly among output sectons. + // So count how many pages are covered each output section referenced + // by GOT relocation. Add 0x8000 because the page address stored + // in the GOT entry is calculated as (value + 0x8000) & ~0xffff. + MipsLocalEntries += (OutSec->getSize() + 0x8000 + 0xfffe) / 0xffff; + } this->Header.sh_size = (Target->GotHeaderEntriesNum + MipsLocalEntries + Entries.size()) * sizeof(uintX_t); @@ -1348,8 +1371,12 @@ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf static bool sortMipsSymbols(const std::pair &L, const std::pair &R) { - if (!L.first->isInGot() || !R.first->isInGot()) - return R.first->isInGot(); + // Sort entries related to non-local preemptible symbols by GOT indexes. + // All other entries go to the first part of GOT in arbitrary order. + bool LIsInLocalGot = !L.first->isInGot() || !L.first->isPreemptible(); + bool RIsInLocalGot = !R.first->isInGot() || !R.first->isPreemptible(); + if (LIsInLocalGot || RIsInLocalGot) + return !RIsInLocalGot; return L.first->GotIndex < R.first->GotIndex; } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1091,10 +1091,17 @@ // of finalizing other sections. The dynamic string table is // finalized once the .dynamic finalizer has added a few last // strings. See DynamicSection::finalize() + // The GOT is finalized at the end to be sure that size of all + // sections referenced by the GOT is calculated already. + // See GotSection::finalize() for (OutputSectionBase *Sec : OutputSections) - if (Sec != Out::DynStrTab && Sec != Out::Dynamic) + if (Sec != Out::DynStrTab && Sec != Out::Dynamic && + Sec != Out::Got) Sec->finalize(); + if (Out::Got) + Out::Got->finalize(); + if (isOutputDynamic()) Out::Dynamic->finalize(); return true; Index: test/ELF/mips-got-redundant.s =================================================================== --- test/ELF/mips-got-redundant.s +++ test/ELF/mips-got-redundant.s @@ -25,21 +25,6 @@ # CHECK-NEXT: Initial: 0x40008 # ^-- glb1 # CHECK-NEXT: } -# CHECK-NEXT: Entry { -# CHECK-NEXT: Address: 0x20014 -# CHECK-NEXT: Access: -32732 -# CHECK-NEXT: Initial: 0x0 -# CHECK-NEXT: } -# CHECK-NEXT: Entry { -# CHECK-NEXT: Address: 0x20018 -# CHECK-NEXT: Access: -32728 -# CHECK-NEXT: Initial: 0x0 -# CHECK-NEXT: } -# CHECK-NEXT: Entry { -# CHECK-NEXT: Address: 0x2001C -# CHECK-NEXT: Access: -32724 -# CHECK-NEXT: Initial: 0x0 -# CHECK-NEXT: } # CHECK-NEXT: ] .text