//
// 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);
}
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);
// 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;
}
#include "Config.h"
#include "lld/Core/LLVM.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/ELF.h"
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);
# 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