diff options
| -rw-r--r-- | lld/ELF/OutputSections.cpp | 44 | ||||
| -rw-r--r-- | lld/ELF/OutputSections.h | 3 | ||||
| -rw-r--r-- | lld/test/ELF/mips-got-redundant.s | 15 | 
3 files changed, 38 insertions, 24 deletions
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 9421c4881fc..8ea9033e8d5 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -115,16 +115,30 @@ template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody &Sym) {      //      // 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<DefinedRegular<ELFT>>(&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,14 @@ unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const {  }  template <class ELFT> void GotSection<ELFT>::finalize() { +  for (const OutputSectionBase<ELFT> *OutSec : MipsOutSections) { +    // Calculate an upper bound of MIPS GOT entries required to store page +    // addresses of local symbols. We assume the worst case - each 64kb +    // page of the output section has at least one GOT relocation against it. +    // Add 0x8000 to the section's size 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 +1370,12 @@ SymbolTableSection<ELFT>::SymbolTableSection(  // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf  static bool sortMipsSymbols(const std::pair<SymbolBody *, unsigned> &L,                              const std::pair<SymbolBody *, unsigned> &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;  } diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index 0b4edb9e355..a35fa1ef34f 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/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 @@ private:    std::vector<const SymbolBody *> Entries;    uint32_t TlsIndexOff = -1;    uint32_t MipsLocalEntries = 0; +  // Output sections referenced by MIPS GOT relocations. +  llvm::SmallPtrSet<const OutputSectionBase<ELFT> *, 10> MipsOutSections;    llvm::DenseMap<uintX_t, size_t> MipsLocalGotPos;    uintX_t getMipsLocalEntryAddr(uintX_t EntryValue); diff --git a/lld/test/ELF/mips-got-redundant.s b/lld/test/ELF/mips-got-redundant.s index 0526042e061..07c3c249f4f 100644 --- a/lld/test/ELF/mips-got-redundant.s +++ b/lld/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  | 

