Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -35,7 +35,6 @@ R_GOT_FROM_END, R_GOT_PAGE_PC, R_GOT_PC, - R_MIPS_GOT, R_MIPS_GOT_LOCAL, R_NEG_TLS, R_PAGE_PC, @@ -60,10 +59,9 @@ }; inline bool refersToGotEntry(RelExpr Expr) { - return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT || - Expr == R_MIPS_GOT_LOCAL || Expr == R_GOT_PAGE_PC || - Expr == R_GOT_PC || Expr == R_GOT_FROM_END || Expr == R_TLSGD || - Expr == R_TLSGD_PC; + return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT_LOCAL || + Expr == R_GOT_PAGE_PC || Expr == R_GOT_PC || Expr == R_GOT_FROM_END || + Expr == R_TLSGD || Expr == R_TLSGD_PC; } struct Relocation { Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -193,13 +193,6 @@ // should be initialized by 'page address'. This address is high 16-bits // of sum the symbol's value and the addend. return Out::Got->getMipsLocalPageOffset(Body.getVA(A)); - case R_MIPS_GOT: - // For non-local symbols GOT entries should contain their full - // addresses. But if such symbol cannot be preempted, we do not - // have to put them into the "global" part of GOT and use dynamic - // linker to determine their actual addresses. That is why we - // create GOT entries for them in the "local" part of GOT. - return Out::Got->getMipsLocalEntryOffset(Body.getVA(A)); case R_PPC_OPD: { uint64_t SymVA = Body.getVA(A); // If we have an undefined weak symbol, we might get here with a symbol Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -113,8 +113,7 @@ void addEntry(SymbolBody &Sym); bool addDynTlsEntry(SymbolBody &Sym); bool addTlsIndex(); - bool empty() const { return MipsLocalEntries == 0 && Entries.empty(); } - uintX_t getMipsLocalEntryOffset(uintX_t EntryValue); + bool empty() const { return Entries.empty(); } uintX_t getMipsLocalPageOffset(uintX_t Addr); uintX_t getGlobalDynAddr(const SymbolBody &B) const; uintX_t getGlobalDynOffset(const SymbolBody &B) const; @@ -134,9 +133,15 @@ uint32_t getTlsIndexOff() { return TlsIndexOff; } private: - std::vector Entries; + enum EntryKind { + MipsLocal, + MipsGlobal, + Regular, + }; + std::vector> Entries; uint32_t TlsIndexOff = -1; uint32_t MipsLocalEntries = 0; + const SymbolBody *MipsFirstGlobalSym = nullptr; // Output sections referenced by MIPS GOT relocations. llvm::SmallPtrSet *, 10> MipsOutSections; llvm::DenseMap MipsLocalGotPos; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -125,22 +125,15 @@ // 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; + } else { + Sym.GotIndex = Entries.size(); + Entries.push_back( + std::make_pair(Sym.isPreemptible() ? MipsGlobal : MipsLocal, &Sym)); } + return; } Sym.GotIndex = Entries.size(); - Entries.push_back(&Sym); + Entries.push_back(std::make_pair(Regular, &Sym)); } template bool GotSection::addDynTlsEntry(SymbolBody &Sym) { @@ -148,8 +141,8 @@ return false; Sym.GlobalDynIndex = Entries.size(); // Global Dynamic TLS entries take two GOT slots. - Entries.push_back(&Sym); - Entries.push_back(nullptr); + Entries.push_back(std::make_pair(Regular, &Sym)); + Entries.push_back(std::make_pair(Regular, nullptr)); return true; } @@ -159,8 +152,8 @@ if (TlsIndexOff != uint32_t(-1)) return false; TlsIndexOff = Entries.size() * sizeof(uintX_t); - Entries.push_back(nullptr); - Entries.push_back(nullptr); + Entries.push_back(std::make_pair(Regular, nullptr)); + Entries.push_back(std::make_pair(Regular, nullptr)); return true; } @@ -169,12 +162,7 @@ GotSection::getMipsLocalPageOffset(uintX_t EntryValue) { // Initialize the entry by the %hi(EntryValue) expression // but without right-shifting. - return getMipsLocalEntryOffset((EntryValue + 0x8000) & ~0xffff); -} - -template -typename GotSection::uintX_t -GotSection::getMipsLocalEntryOffset(uintX_t EntryValue) { + EntryValue = (EntryValue + 0x8000) & ~0xffff; // Take into account MIPS GOT header. // See comment in the GotSection::writeTo. size_t NewIndex = MipsLocalGotPos.size() + 2; @@ -197,7 +185,7 @@ template const SymbolBody *GotSection::getMipsFirstGlobalEntry() const { - return Entries.empty() ? nullptr : Entries.front(); + return MipsFirstGlobalSym; } template @@ -206,19 +194,40 @@ } template void GotSection::finalize() { - if (Config->EMachine == EM_MIPS) + if (Config->EMachine == EM_MIPS) { // Take into account MIPS GOT header. // See comment in the GotSection::writeTo. - MipsLocalEntries += 2; - for (const OutputSectionBase *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; + size_t PageEntries = 2; + for (const OutputSectionBase *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. + PageEntries += (OutSec->getSize() + 0x8000 + 0xfffe) / 0xffff; + Entries.insert(Entries.begin(), PageEntries, + std::make_pair(MipsLocal, nullptr)); + // Sort GOT entries by type: local entries, global entries. + // Use stable sort to keep order of global entries because + // we have sorted dynamic symbol table using this order already. + std::stable_sort(std::begin(Entries), std::end(Entries), + [](const std::pair &A, + const std::pair &B) { + return A.first < B.first; + }); + for (size_t I = 0, E = Entries.size(); I < E; ++I) { + EntryKind Kind = Entries[I].first; + SymbolBody *Sym = Entries[I].second; + if (Kind == MipsLocal) + ++MipsLocalEntries; + if (Kind == MipsGlobal && !MipsFirstGlobalSym) + MipsFirstGlobalSym = Sym; + if (Sym) { + Sym->GotIndex = I; + } + } } - this->Header.sh_size = (MipsLocalEntries + Entries.size()) * sizeof(uintX_t); + this->Header.sh_size = Entries.size() * sizeof(uintX_t); } template void GotSection::writeTo(uint8_t *Buf) { @@ -244,8 +253,8 @@ uint8_t *Entry = Buf + L.second * sizeof(uintX_t); write(Entry, L.first); } - Buf += MipsLocalEntries * sizeof(uintX_t); - for (const SymbolBody *B : Entries) { + for (const auto &E : Entries) { + const SymbolBody *B = E.second; uint8_t *Entry = Buf; Buf += sizeof(uintX_t); if (!B) Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -143,8 +143,7 @@ } template typename ELFT::uint SymbolBody::getGotOffset() const { - return (Out::Got->getMipsLocalEntriesNum() + GotIndex) * - sizeof(typename ELFT::uint); + return GotIndex * sizeof(typename ELFT::uint); } template typename ELFT::uint SymbolBody::getGotPltVA() const { Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -1292,8 +1292,6 @@ case R_MIPS_CALL16: if (S.isLocal()) return R_MIPS_GOT_LOCAL; - if (!S.isPreemptible()) - return R_MIPS_GOT; return R_GOT_OFF; } } Index: test/ELF/mips-got16.s =================================================================== --- test/ELF/mips-got16.s +++ test/ELF/mips-got16.s @@ -17,7 +17,7 @@ # CHECK-NEXT: 10014: 21 08 90 04 addi $8, $8, -28668 # CHECK-NEXT: 10018: 8f 88 80 20 lw $8, -32736($gp) # CHECK-NEXT: 1001c: 21 08 10 04 addi $8, $8, 4100 -# CHECK-NEXT: 10020: 8f 88 80 24 lw $8, -32732($gp) +# CHECK-NEXT: 10020: 8f 88 80 28 lw $8, -32728($gp) # CHECK-NEXT: 10024: 21 08 10 08 addi $8, $8, 4104 # CHECK-NEXT: 10028: 8f 88 80 2c lw $8, -32724($gp) # @@ -69,14 +69,14 @@ # GOT-NEXT: Entry { # GOT-NEXT: Address: 0x20014 # GOT-NEXT: Access: -32732 -# GOT-NEXT: Initial: 0x51008 -# ^-- 'bar' address +# GOT-NEXT: Initial: 0x0 +# ^-- redundant unused entry # GOT-NEXT: } # GOT-NEXT: Entry { # GOT-NEXT: Address: 0x20018 # GOT-NEXT: Access: -32728 -# GOT-NEXT: Initial: 0x0 -# ^-- redundant unused entry +# GOT-NEXT: Initial: 0x51008 +# ^-- 'bar' address # GOT-NEXT: } # GOT-NEXT: ] # GOT-NEXT: Global entries [