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 @@ -91,16 +91,34 @@ template void GotSection::addEntry(SymbolBody &Sym) { if (Config->EMachine == EM_MIPS) { - if (Sym.isPreemptible()) - // All symbols with MIPS GOT entries should be represented - // in the dynamic symbols table. See "Global Offset Table" in Chapter 5: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - Sym.MustBeInDynSym = true; - else { - // FIXME (simon): Do not add so many redundant entries. + if (Sym.isLocal()) { + // Local symbol which requires GOT entry initialized by "page" + // address. This address is high 16 bits of sum of the symbol value + // and the relocation addend. 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 GotSection::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 symbols with MIPS GOT entries should be represented + // in the dynamic symbols table. See "Global Offset Table" in Chapter 5: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + Sym.MustBeInDynSym = true; } Sym.GotIndex = Entries.size(); Entries.push_back(&Sym); @@ -167,6 +185,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); @@ -1324,8 +1351,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 @@ -1083,10 +1083,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