summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/Config.h1
-rw-r--r--lld/ELF/Driver.cpp1
-rw-r--r--lld/ELF/InputFiles.h3
-rw-r--r--lld/ELF/InputSection.cpp32
-rw-r--r--lld/ELF/Options.td5
-rw-r--r--lld/ELF/Relocations.cpp25
-rw-r--r--lld/ELF/Symbols.h10
-rw-r--r--lld/ELF/SyntheticSections.cpp536
-rw-r--r--lld/ELF/SyntheticSections.h161
-rw-r--r--lld/ELF/Writer.cpp3
-rw-r--r--lld/test/ELF/Inputs/mips-mgot-1.s10
-rw-r--r--lld/test/ELF/Inputs/mips-mgot-2.s17
-rw-r--r--lld/test/ELF/mips-abs-got.s36
-rw-r--r--lld/test/ELF/mips-dynamic.s2
-rw-r--r--lld/test/ELF/mips-got-script.s10
-rw-r--r--lld/test/ELF/mips-got-weak.s157
-rw-r--r--lld/test/ELF/mips-mgot.s129
-rw-r--r--lld/test/ELF/mips-plt-copy.s8
-rw-r--r--lld/test/ELF/mips-sto-plt.s18
-rw-r--r--lld/test/ELF/mips-tls-64.s72
-rw-r--r--lld/test/ELF/mips-tls-static.s4
-rw-r--r--lld/test/ELF/mips-tls.s70
22 files changed, 851 insertions, 459 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 60276f95ff3..07605b2aff3 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -194,6 +194,7 @@ struct Configuration {
uint16_t EMachine = llvm::ELF::EM_NONE;
llvm::Optional<uint64_t> ImageBase;
uint64_t MaxPageSize;
+ uint64_t MipsGotSize;
uint64_t ZStackSize;
unsigned LTOPartitions;
unsigned LTOO;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 0290084493f..0d3e0835c98 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -725,6 +725,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1);
Config->LTOSampleProfile = Args.getLastArgValue(OPT_lto_sample_profile);
Config->MapFile = Args.getLastArgValue(OPT_Map);
+ Config->MipsGotSize = args::getInteger(Args, OPT_mips_got_size, 0xfff0);
Config->MergeArmExidx =
Args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true);
Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec);
diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h
index 65de20483a9..4f5df6f224c 100644
--- a/lld/ELF/InputFiles.h
+++ b/lld/ELF/InputFiles.h
@@ -120,6 +120,9 @@ public:
static bool IsInGroup;
static uint32_t NextGroupId;
+ // Index of MIPS GOT built for this file.
+ llvm::Optional<size_t> MipsGotIndex;
+
protected:
InputFile(Kind K, MemoryBufferRef M);
std::vector<InputSectionBase *> Sections;
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 32f1f4846f7..b8e4659b921 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -477,8 +477,8 @@ static uint64_t getARMStaticBase(const Symbol &Sym) {
return OS->PtLoad->FirstSec->Addr;
}
-static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
- const Symbol &Sym, RelExpr Expr) {
+static uint64_t getRelocTargetVA(const InputFile &File, RelType Type, int64_t A,
+ uint64_t P, const Symbol &Sym, RelExpr Expr) {
switch (Expr) {
case R_INVALID:
return 0;
@@ -516,9 +516,9 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
case R_TLSDESC_CALL:
llvm_unreachable("cannot relocate hint relocs");
case R_MIPS_GOTREL:
- return Sym.getVA(A) - InX::MipsGot->getGp();
+ return Sym.getVA(A) - InX::MipsGot->getGp(&File);
case R_MIPS_GOT_GP:
- return InX::MipsGot->getGp() + A;
+ return InX::MipsGot->getGp(&File) + A;
case R_MIPS_GOT_GP_PC: {
// R_MIPS_LO16 expression has R_MIPS_GOT_GP_PC type iif the target
// is _gp_disp symbol. In that case we should use the following
@@ -527,7 +527,7 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
// microMIPS variants of these relocations use slightly different
// expressions: AHL + GP - P + 3 for %lo() and AHL + GP - P - 1 for %hi()
// to correctly handle less-sugnificant bit of the microMIPS symbol.
- uint64_t V = InX::MipsGot->getGp() + A - P;
+ uint64_t V = InX::MipsGot->getGp(&File) + A - P;
if (Type == R_MIPS_LO16 || Type == R_MICROMIPS_LO16)
V += 4;
if (Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_HI16)
@@ -538,21 +538,24 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P,
// If relocation against MIPS local symbol requires GOT entry, this entry
// should be initialized by 'page address'. This address is high 16-bits
// of sum the symbol's value and the addend.
- return InX::MipsGot->getVA() + InX::MipsGot->getPageEntryOffset(Sym, A) -
- InX::MipsGot->getGp();
+ return InX::MipsGot->getVA() +
+ InX::MipsGot->getPageEntryOffset(File, Sym, A) -
+ InX::MipsGot->getGp(&File);
case R_MIPS_GOT_OFF:
case R_MIPS_GOT_OFF32:
// In case of MIPS if a GOT relocation has non-zero addend this addend
// should be applied to the GOT entry content not to the GOT entry offset.
// That is why we use separate expression type.
- return InX::MipsGot->getVA() + InX::MipsGot->getSymEntryOffset(Sym, A) -
- InX::MipsGot->getGp();
+ return InX::MipsGot->getVA() +
+ InX::MipsGot->getSymEntryOffset(File, Sym, A) -
+ InX::MipsGot->getGp(&File);
case R_MIPS_TLSGD:
- return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() +
- InX::MipsGot->getGlobalDynOffset(Sym) - InX::MipsGot->getGp();
+ return InX::MipsGot->getVA() +
+ InX::MipsGot->getGlobalDynOffset(File, Sym) -
+ InX::MipsGot->getGp(&File);
case R_MIPS_TLSLD:
- return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() +
- InX::MipsGot->getTlsIndexOff() - InX::MipsGot->getGp();
+ return InX::MipsGot->getVA() + InX::MipsGot->getTlsIndexOffset(File) -
+ InX::MipsGot->getGp(&File);
case R_PAGE_PC:
case R_PLT_PAGE_PC: {
uint64_t Dest;
@@ -751,7 +754,8 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
uint64_t AddrLoc = getOutputSection()->Addr + Offset;
RelExpr Expr = Rel.Expr;
uint64_t TargetVA = SignExtend64(
- getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits);
+ getRelocTargetVA(*File, Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr),
+ Bits);
switch (Expr) {
case R_RELAX_GOT_PC:
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 256dc5a4496..d9501587583 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -480,3 +480,8 @@ def: F<"EB">;
def: F<"EL">;
def: JoinedOrSeparate<["-"], "G">;
def: F<"Qy">;
+
+// Hidden option used for testing MIPS multi-GOT implementation.
+defm mips_got_size:
+ Eq<"mips-got-size", "Max size of a single MIPS GOT. 0x10000 by default.">,
+ Flags<[HelpHidden]>;
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 2e3d4f192cc..64b23ab87de 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -85,27 +85,16 @@ static std::string getLocation(InputSectionBase &S, const Symbol &Sym,
// pollute other `handleTlsRelocation` by MIPS `ifs` statements.
// Mips has a custom MipsGotSection that handles the writing of GOT entries
// without dynamic relocations.
-template <class ELFT>
static unsigned handleMipsTlsRelocation(RelType Type, Symbol &Sym,
InputSectionBase &C, uint64_t Offset,
int64_t Addend, RelExpr Expr) {
if (Expr == R_MIPS_TLSLD) {
- if (InX::MipsGot->addTlsIndex() && Config->Pic)
- InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::MipsGot,
- InX::MipsGot->getTlsIndexOff(), nullptr);
+ InX::MipsGot->addTlsIndex(*C.File);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
-
if (Expr == R_MIPS_TLSGD) {
- if (InX::MipsGot->addDynTlsEntry(Sym) && Sym.IsPreemptible) {
- uint64_t Off = InX::MipsGot->getGlobalDynOffset(Sym);
- InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::MipsGot, Off,
- &Sym);
- if (Sym.IsPreemptible)
- InX::RelaDyn->addReloc(Target->TlsOffsetRel, InX::MipsGot,
- Off + Config->Wordsize, &Sym);
- }
+ InX::MipsGot->addDynTlsEntry(*C.File, Sym);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
@@ -184,7 +173,7 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
if (Config->EMachine == EM_ARM)
return handleARMTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr);
if (Config->EMachine == EM_MIPS)
- return handleMipsTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr);
+ return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr);
if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
Config->Shared) {
@@ -476,7 +465,6 @@ static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value,
Sym.PltIndex = Old.PltIndex;
Sym.GotIndex = Old.GotIndex;
Sym.VerdefIndex = Old.VerdefIndex;
- Sym.IsInGlobalMipsGot = Old.IsInGlobalMipsGot;
Sym.IsPreemptible = true;
Sym.ExportDynamic = true;
Sym.IsUsedInRegularObj = true;
@@ -816,7 +804,7 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
// a dynamic relocation.
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
if (Config->EMachine == EM_MIPS)
- InX::MipsGot->addEntry(Sym, Addend, Expr);
+ InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
return;
}
}
@@ -1002,10 +990,7 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
// See "Global Offset Table" in Chapter 5 in the following document
// for detailed description:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- InX::MipsGot->addEntry(Sym, Addend, Expr);
- if (Sym.isTls() && Sym.IsPreemptible)
- InX::RelaDyn->addReloc(Target->TlsGotRel, InX::MipsGot,
- Sym.getGotOffset(), &Sym);
+ InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
} else if (!Sym.isInGot()) {
addGotEntry<ELFT>(Sym);
}
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index f0912d29b75..8c9513b9368 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -158,19 +158,13 @@ protected:
uint8_t StOther, uint8_t Type)
: File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding),
Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false),
- IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false),
- IsInIgot(false), IsPreemptible(false), Used(!Config->GcSections),
- NeedsTocRestore(false) {}
+ IsInIplt(false), IsInIgot(false), IsPreemptible(false),
+ Used(!Config->GcSections), NeedsTocRestore(false) {}
public:
// True the symbol should point to its PLT entry.
// For SharedSymbol only.
unsigned NeedsPltAddr : 1;
- // True if this symbol has an entry in the global part of MIPS GOT.
- unsigned IsInGlobalMipsGot : 1;
-
- // True if this symbol is referenced by 32-bit GOT relocations.
- unsigned Is32BitMipsGot : 1;
// True if this symbol is in the Iplt sub-section of the Plt.
unsigned IsInIplt : 1;
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 1c66bcbe597..cd0d3fe525c 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -29,6 +29,7 @@
#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "lld/Common/Version.h"
+#include "llvm/ADT/SetOperations.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
#include "llvm/Object/Decompressor.h"
@@ -636,180 +637,344 @@ void GotSection::writeTo(uint8_t *Buf) {
relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size);
}
+static uint64_t getMipsPageAddr(uint64_t Addr) {
+ return (Addr + 0x8000) & ~0xffff;
+}
+
+static uint64_t getMipsPageCount(uint64_t Size) {
+ return (Size + 0xfffe) / 0xffff + 1;
+}
+
MipsGotSection::MipsGotSection()
: SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16,
".got") {}
-void MipsGotSection::addEntry(Symbol &Sym, int64_t Addend, RelExpr Expr) {
- // For "true" local symbols which can be referenced from the same module
- // only compiler creates two instructions for address loading:
- //
- // lw $8, 0($gp) # R_MIPS_GOT16
- // addi $8, $8, 0 # R_MIPS_LO16
- //
- // The first instruction loads high 16 bits of the symbol address while
- // the second adds an offset. That allows to reduce number of required
- // GOT entries because only one global offset table entry is necessary
- // for every 64 KBytes of local data. So for local symbols we need to
- // allocate number of GOT entries to hold all required "page" addresses.
- //
- // All global symbols (hidden and regular) considered by compiler uniformly.
- // It always generates a single `lw` instruction and R_MIPS_GOT16 relocation
- // to load address of the symbol. So for each such symbol we need to
- // allocate dedicated GOT entry to store its address.
- //
- // If a symbol is preemptible we need help of dynamic linker to get its
- // final address. The corresponding GOT entries are allocated in the
- // "global" part of GOT. Entries for non preemptible global symbol allocated
- // in the "local" part of GOT.
- //
- // See "Global Offset Table" in Chapter 5:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+void MipsGotSection::addEntry(InputFile &File, Symbol &Sym, int64_t Addend,
+ RelExpr Expr) {
+ FileGot &G = getGot(File);
if (Expr == R_MIPS_GOT_LOCAL_PAGE) {
- // 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.
- PageIndexMap.insert({Sym.getOutputSection(), 0});
- return;
- }
- if (Sym.isTls()) {
- // GOT entries created for MIPS TLS relocations behave like
- // almost GOT entries from other ABIs. They go to the end
- // of the global offset table.
- Sym.GotIndex = TlsEntries.size();
- TlsEntries.push_back(&Sym);
- return;
- }
- auto AddEntry = [&](Symbol &S, uint64_t A, GotEntries &Items) {
- if (S.isInGot() && !A)
- return;
- size_t NewIndex = Items.size();
- if (!EntryIndexMap.insert({{&S, A}, NewIndex}).second)
- return;
- Items.emplace_back(&S, A);
- if (!A)
- S.GotIndex = NewIndex;
- };
- if (Sym.IsPreemptible) {
- // Ignore addends for preemptible symbols. They got single GOT entry anyway.
- AddEntry(Sym, 0, GlobalEntries);
- Sym.IsInGlobalMipsGot = true;
- } else if (Expr == R_MIPS_GOT_OFF32) {
- AddEntry(Sym, Addend, LocalEntries32);
- Sym.Is32BitMipsGot = true;
- } else {
- // Hold local GOT entries accessed via a 16-bit index separately.
- // That allows to write them in the beginning of the GOT and keep
- // their indexes as less as possible to escape relocation's overflow.
- AddEntry(Sym, Addend, LocalEntries);
- }
+ if (const OutputSection *OS = Sym.getOutputSection())
+ G.PagesMap.insert({OS, {}});
+ else
+ G.Local16.insert({{nullptr, getMipsPageAddr(Sym.getVA(Addend))}, 0});
+ } else if (Sym.isTls())
+ G.Tls.insert({&Sym, 0});
+ else if (Sym.IsPreemptible && Expr == R_ABS)
+ G.Relocs.insert({&Sym, 0});
+ else if (Sym.IsPreemptible)
+ G.Global.insert({&Sym, 0});
+ else if (Expr == R_MIPS_GOT_OFF32)
+ G.Local32.insert({{&Sym, Addend}, 0});
+ else
+ G.Local16.insert({{&Sym, Addend}, 0});
}
-bool MipsGotSection::addDynTlsEntry(Symbol &Sym) {
- if (Sym.GlobalDynIndex != -1U)
- return false;
- Sym.GlobalDynIndex = TlsEntries.size();
- // Global Dynamic TLS entries take two GOT slots.
- TlsEntries.push_back(nullptr);
- TlsEntries.push_back(&Sym);
- return true;
+void MipsGotSection::addDynTlsEntry(InputFile &File, Symbol &Sym) {
+ getGot(File).DynTlsSymbols.insert({&Sym, 0});
}
-// Reserves TLS entries for a TLS module ID and a TLS block offset.
-// In total it takes two GOT slots.
-bool MipsGotSection::addTlsIndex() {
- if (TlsIndexOff != uint32_t(-1))
- return false;
- TlsIndexOff = TlsEntries.size() * Config->Wordsize;
- TlsEntries.push_back(nullptr);
- TlsEntries.push_back(nullptr);
- return true;
+void MipsGotSection::addTlsIndex(InputFile &File) {
+ getGot(File).DynTlsSymbols.insert({nullptr, 0});
}
-static uint64_t getMipsPageAddr(uint64_t Addr) {
- return (Addr + 0x8000) & ~0xffff;
+size_t MipsGotSection::FileGot::getEntriesNum() const {
+ return getPageEntriesNum() + Local16.size() + Global.size() + Relocs.size() +
+ Tls.size() + DynTlsSymbols.size() * 2;
}
-static uint64_t getMipsPageCount(uint64_t Size) {
- return (Size + 0xfffe) / 0xffff + 1;
+size_t MipsGotSection::FileGot::getPageEntriesNum() const {
+ size_t Num = 0;
+ for (const std::pair<const OutputSection *, FileGot::PageBlock> &P : PagesMap)
+ Num += P.second.Count;
+ return Num;
}
-uint64_t MipsGotSection::getPageEntryOffset(const Symbol &B,
- int64_t Addend) const {
- const OutputSection *OutSec = B.getOutputSection();
- uint64_t SecAddr = getMipsPageAddr(OutSec->Addr);
- uint64_t SymAddr = getMipsPageAddr(B.getVA(Addend));
- uint64_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff;
- assert(Index < PageEntriesNum);
- return (HeaderEntriesNum + Index) * Config->Wordsize;
+size_t MipsGotSection::FileGot::getIndexedEntriesNum() const {
+ size_t Count = getPageEntriesNum() + Local16.size() + Global.size();
+ // If there are relocation-only entries in the GOT, TLS entries
+ // are allocated after them. TLS entries should be addressable
+ // by 16-bit index so count both reloc-only and TLS entries.
+ if (!Tls.empty() || !DynTlsSymbols.empty())
+ Count += Relocs.size() + Tls.size() + DynTlsSymbols.size() * 2;
+ return Count;
}
-uint64_t MipsGotSection::getSymEntryOffset(const Symbol &B,
- int64_t Addend) const {
- // Calculate offset of the GOT entries block: TLS, global, local.
- uint64_t Index = HeaderEntriesNum + PageEntriesNum;
- if (B.isTls())
- Index += LocalEntries.size() + LocalEntries32.size() + GlobalEntries.size();
- else if (B.IsInGlobalMipsGot)
- Index += LocalEntries.size() + LocalEntries32.size();
- else if (B.Is32BitMipsGot)
- Index += LocalEntries.size();
- // Calculate offset of the GOT entry in the block.
- if (B.isInGot())
- Index += B.GotIndex;
- else {
- auto It = EntryIndexMap.find({&B, Addend});
- assert(It != EntryIndexMap.end());
- Index += It->second;
+MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &F) {
+ if (!F.MipsGotIndex.hasValue()) {
+ Gots.emplace_back();
+ Gots.back().File = &F;
+ F.MipsGotIndex = Gots.size() - 1;
+ }
+ return Gots[*F.MipsGotIndex];
+}
+
+uint64_t MipsGotSection::getPageEntryOffset(const InputFile &F,
+ const Symbol &Sym,
+ int64_t Addend) const {
+ const FileGot &G = Gots[*F.MipsGotIndex];
+ uint64_t Index = 0;
+ if (const OutputSection *OutSec = Sym.getOutputSection()) {
+ uint64_t SecAddr = getMipsPageAddr(OutSec->Addr);
+ uint64_t SymAddr = getMipsPageAddr(Sym.getVA(Addend));
+ Index = G.PagesMap.lookup(OutSec).FirstIndex + (SymAddr - SecAddr) / 0xffff;
+ } else {
+ Index = G.Local16.lookup({nullptr, getMipsPageAddr(Sym.getVA(Addend))});
}
return Index * Config->Wordsize;
}
-uint64_t MipsGotSection::getTlsOffset() const {
- return (getLocalEntriesNum() + GlobalEntries.size()) * Config->Wordsize;
+uint64_t MipsGotSection::getSymEntryOffset(const InputFile &F, const Symbol &S,
+ int64_t Addend) const {
+ const FileGot &G = Gots[*F.MipsGotIndex];
+ Symbol *Sym = const_cast<Symbol *>(&S);
+ if (Sym->isTls())
+ return G.Tls.find(Sym)->second * Config->Wordsize;
+ if (Sym->IsPreemptible)
+ return G.Global.find(Sym)->second * Config->Wordsize;
+ return G.Local16.find({Sym, Addend})->second * Config->Wordsize;
}
-uint64_t MipsGotSection::getGlobalDynOffset(const Symbol &B) const {
- return B.GlobalDynIndex * Config->Wordsize;
+uint64_t MipsGotSection::getTlsIndexOffset(const InputFile &F) const {
+ const FileGot &G = Gots[*F.MipsGotIndex];
+ return G.DynTlsSymbols.find(nullptr)->second * Config->Wordsize;
+}
+
+uint64_t MipsGotSection::getGlobalDynOffset(const InputFile &F,
+ const Symbol &S) const {
+ const FileGot &G = Gots[*F.MipsGotIndex];
+ Symbol *Sym = const_cast<Symbol *>(&S);
+ return G.DynTlsSymbols.find(Sym)->second * Config->Wordsize;
}
const Symbol *MipsGotSection::getFirstGlobalEntry() const {
- return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first;
+ if (Gots.empty())
+ return nullptr;
+ const FileGot &PrimGot = Gots.front();
+ if (!PrimGot.Global.empty())
+ return PrimGot.Global.front().first;
+ if (!PrimGot.Relocs.empty())
+ return PrimGot.Relocs.front().first;
+ return nullptr;
}
unsigned MipsGotSection::getLocalEntriesNum() const {
- return HeaderEntriesNum + PageEntriesNum + LocalEntries.size() +
- LocalEntries32.size();
+ if (Gots.empty())
+ return HeaderEntriesNum;
+ return HeaderEntriesNum + Gots.front().getPageEntriesNum() +
+ Gots.front().Local16.size();
+}
+
+bool MipsGotSection::tryMergeGots(FileGot &Dst, FileGot &Src, bool IsPrimary) {
+ FileGot Tmp = Dst;
+ set_union(Tmp.PagesMap, Src.PagesMap);
+ set_union(Tmp.Local16, Src.Local16);
+ set_union(Tmp.Global, Src.Global);
+ set_union(Tmp.Relocs, Src.Relocs);
+ set_union(Tmp.Tls, Src.Tls);
+ set_union(Tmp.DynTlsSymbols, Src.DynTlsSymbols);
+
+ size_t Count = IsPrimary ? HeaderEntriesNum : 0;
+ Count += Tmp.getIndexedEntriesNum();
+
+ if (Count * Config->Wordsize > Config->MipsGotSize)
+ return false;
+
+ std::swap(Tmp, Dst);
+ return true;
}
void MipsGotSection::finalizeContents() { updateAllocSize(); }
bool MipsGotSection::updateAllocSize() {
- PageEntriesNum = 0;
- for (std::pair<const OutputSection *, size_t> &P : PageIndexMap) {
- // For each output section referenced by GOT page relocations calculate
- // and save into PageIndexMap 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. And take in account the case when the section intersects
- // page boundaries.
- P.second = PageEntriesNum;
- PageEntriesNum += getMipsPageCount(P.first->Size);
- }
- Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) *
- Config->Wordsize;
+ Size = HeaderEntriesNum * Config->Wordsize;
+ for (const FileGot &G : Gots)
+ Size += G.getEntriesNum() * Config->Wordsize;
return false;
}
+template <class ELFT> void MipsGotSection::build() {
+ if (Gots.empty())
+ return;
+
+ std::vector<FileGot> MergedGots(1);
+
+ // For each GOT move non-preemptible symbols from the `Global`
+ // to `Local16` list. Preemptible symbol might become non-preemptible
+ // one if, for example, it gets a related copy relocation.
+ for (FileGot &Got : Gots) {
+ for (auto &P: Got.Global)
+ if (!P.first->IsPreemptible)
+ Got.Local16.insert({{P.first, 0}, 0});
+ Got.Global.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+ return !P.first->IsPreemptible;
+ });
+ }
+
+ // For each GOT remove "reloc-only" entry if there is "global"
+ // entry for the same symbol. And add local entries which indexed
+ // using 32-bit value at the end of 16-bit entries.
+ for (FileGot &Got : Gots) {
+ Got.Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+ return Got.Global.count(P.first);
+ });
+ set_union(Got.Local16, Got.Local32);
+ Got.Local32.clear();
+ }
+
+ // Evaluate number of "reloc-only" entries in the resulting GOT.
+ // To do that put all unique "reloc-only" and "global" entries
+ // from all GOTs to the future primary GOT.
+ FileGot *PrimGot = &MergedGots.front();
+ for (FileGot &Got : Gots) {
+ set_union(PrimGot->Relocs, Got.Global);
+ set_union(PrimGot->Relocs, Got.Relocs);
+ Got.Relocs.clear();
+ }
+
+ // Evaluate number of "page" entries in each GOT.
+ for (FileGot &Got : Gots) {
+ for (std::pair<const OutputSection *, FileGot::PageBlock> &P :
+ Got.PagesMap) {
+ const OutputSection *OS = P.first;
+ uint64_t SecSize = 0;
+ for (BaseCommand *Cmd : OS->SectionCommands) {
+ if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd))
+ for (InputSection *IS : ISD->Sections) {
+ uint64_t Off = alignTo(SecSize, IS->Alignment);
+ SecSize = Off + IS->getSize();
+ }
+ }
+ P.second.Count = getMipsPageCount(SecSize);
+ }
+ }
+
+ // Merge GOTs. Try to join as much as possible GOTs but do not
+ // exceed maximum GOT size. In case of overflow create new GOT
+ // and continue merging.
+ for (FileGot &SrcGot : Gots) {
+ FileGot &DstGot = MergedGots.back();
+ InputFile *File = SrcGot.File;
+ if (!tryMergeGots(DstGot, SrcGot, &DstGot == PrimGot)) {
+ MergedGots.emplace_back();
+ std::swap(MergedGots.back(), SrcGot);
+ }
+ File->MipsGotIndex = MergedGots.size() - 1;
+ }
+ std::swap(Gots, MergedGots);
+
+ // Reduce number of "reloc-only" entries in the primary GOT
+ // by substracting "global" entries exist in the primary GOT.
+ PrimGot = &Gots.front();
+ PrimGot->Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) {
+ return PrimGot->Global.count(P.first);
+ });
+
+ // Calculate indexes for each GOT entry.
+ size_t Index = HeaderEntriesNum;
+ for (FileGot &Got : Gots) {
+ Got.StartIndex = &Got == PrimGot ? 0 : Index;
+ for (std::pair<const OutputSection *, FileGot::PageBlock> &P :
+ Got.PagesMap) {
+ // For each output section referenced by GOT page relocations calculate
+ // and save into PagesMap 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. And take in account the case when the section intersects
+ // page boundaries.
+ P.second.FirstIndex = Index;
+ Index += P.second.Count;
+ }
+ for (auto &P: Got.Local16)
+ P.second = Index++;
+ for (auto &P: Got.Global)
+ P.second = Index++;
+ for (auto &P: Got.Relocs)
+ P.second = Index++;
+ for (auto &P: Got.Tls)
+ P.second = Index++;
+ for (auto &P: Got.DynTlsSymbols) {
+ P.second = Index;
+ Index += 2;
+ }
+ }
+
+ // Update Symbol::GotIndex field to use this
+ // value later in the `sortMipsSymbols` function.
+ for (auto &P : PrimGot->Global)
+ P.first->GotIndex = P.second;
+ for (auto &P : PrimGot->Relocs)
+ P.first->GotIndex = P.second;
+
+ // Create dynamic relocations.
+ for (FileGot &Got : Gots) {
+ // Create dynamic relocations for TLS entries.
+ for (std::pair<Symbol *, size_t> &P : Got.Tls) {
+ Symbol *S = P.first;
+ uint64_t Offset = P.second * Config->Wordsize;
+ if (S->IsPreemptible)
+ InX::RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S);
+ }
+ for (std::pair<Symbol *, size_t> &P : Got.DynTlsSymbols) {
+ Symbol *S = P.first;
+ uint64_t Offset = P.second * Config->Wordsize;
+ if (S == nullptr) {
+ if (!Config->Pic)
+ continue;
+ InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
+ } else {
+ if (!P.first->IsPreemptible)
+ continue;
+ InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
+ Offset += Config->Wordsize;
+ InX::RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S);
+ }
+ }
+
+ // Do not create dynamic relocations for non-TLS
+ // entries in the primary GOT.
+ if (&Got == PrimGot)
+ continue;
+
+ // Dynamic relocations for "global" entries.
+ for (const std::pair<Symbol *, size_t> &P : Got.Global) {
+ uint64_t Offset = P.second * Config->Wordsize;
+ InX::RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first);
+ }
+ if (!Config->Pic)
+ continue;
+ // Dynamic relocations for "local" entries in case of PIC.
+ for (const std::pair<const OutputSection *, FileGot::PageBlock> &L :
+ Got.PagesMap) {
+ size_t PageCount = L.second.Count;
+ for (size_t PI = 0; PI < PageCount; ++PI) {
+ uint64_t Offset = (L.second.FirstIndex + PI) * Config->Wordsize;
+ InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first,
+ int64_t(PI * 0x10000)});
+ }
+ }
+ for (const std::pair<GotEntry, size_t> &P : Got.Local16) {
+ uint64_t Offset = P.second * Config->Wordsize;
+ InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, true,
+ P.first.first, P.first.second});
+ }
+ }
+}
+
bool MipsGotSection::empty() const {
// We add the .got section to the result for dynamic MIPS target because
// its address and properties are mentioned in the .dynamic section.
return Config->Relocatable;
}
-uint64_t MipsGotSection::getGp() const { return ElfSym::MipsGp->getVA(0); }
+uint64_t MipsGotSection::getGp(const InputFile *F) const {
+ // For files without related GOT or files refer a primary GOT
+ // returns "common" _gp value. For secondary GOTs calculate
+ // individual _gp values.
+ if (!F || !F->MipsGotIndex.hasValue() || *F->MipsGotIndex == 0)
+ return ElfSym::MipsGp->getVA(0);
+ return getVA() + Gots[*F->MipsGotIndex].StartIndex * Config->Wordsize +
+ 0x7ff0;
+}
void MipsGotSection::writeTo(uint8_t *Buf) {
// Set the MSB of the second GOT slot. This is not required by any
@@ -827,49 +992,47 @@ void MipsGotSection::writeTo(uint8_t *Buf) {
// keep doing this for now. We really need to revisit this to see
// if we had to do this.
writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1));
- Buf += HeaderEntriesNum * Config->Wordsize;
- // Write 'page address' entries to the local part of the GOT.
- for (std::pair<const OutputSection *, size_t> &L : PageIndexMap) {
- size_t PageCount = getMipsPageCount(L.first->Size);
- uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
- for (size_t PI = 0; PI < PageCount; ++PI) {
- uint8_t *Entry = Buf + (L.second + PI) * Config->Wordsize;
- writeUint(Entry, FirstPageAddr + PI * 0x10000);
- }
- }
- Buf += PageEntriesNum * Config->Wordsize;
- auto AddEntry = [&](const GotEntry &SA) {
- uint8_t *Entry = Buf;
- Buf += Config->Wordsize;
- const Symbol *Sym = SA.first;
- uint64_t VA = Sym->getVA(SA.second);
- if (Sym->StOther & STO_MIPS_MICROMIPS)
- VA |= 1;
- writeUint(Entry, VA);
- };
- std::for_each(std::begin(LocalEntries), std::end(LocalEntries), AddEntry);
- std::for_each(std::begin(LocalEntries32), std::end(LocalEntries32), AddEntry);
- std::for_each(std::begin(GlobalEntries), std::end(GlobalEntries), AddEntry);
- // Initialize TLS-related GOT entries. If the entry has a corresponding
- // dynamic relocations, leave it initialized by zero. Write down adjusted
- // TLS symbol's values otherwise. To calculate the adjustments use offsets
- // for thread-local storage.
- // https://www.linux-mips.org/wiki/NPTL
- if (TlsIndexOff != -1U && !Config->Pic)
- writeUint(Buf + TlsIndexOff, 1);
- for (const Symbol *B : TlsEntries) {
- if (!B || B->IsPreemptible)
- continue;
- uint64_t VA = B->getVA();
- if (B->GotIndex != -1U) {
- uint8_t *Entry = Buf + B->GotIndex * Config->Wordsize;
- writeUint(Entry, VA - 0x7000);
+ for (const FileGot &G : Gots) {
+ auto Write = [&](size_t I, const Symbol *S, int64_t A) {
+ uint64_t VA = A;
+ if (S) {
+ VA = S->getVA(A);
+ if (S->StOther & STO_MIPS_MICROMIPS)
+ VA |= 1;
+ }
+ writeUint(Buf + I * Config->Wordsize, VA);
+ };
+ // Write 'page address' entries to the local part of the GOT.
+ for (const std::pair<const OutputSection *, FileGot::PageBlock> &L :
+ G.PagesMap) {
+ size_t PageCount = L.second.Count;
+ uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr);
+ for (size_t PI = 0; PI < PageCount; ++PI)
+ Write(L.second.FirstIndex + PI, nullptr, FirstPageAddr + PI * 0x10000);
}
- if (B->GlobalDynIndex != -1U) {
- uint8_t *Entry = Buf + B->GlobalDynIndex * Config->Wordsize;
- writeUint(Entry, 1);
- Entry += Config->Wordsize;
- writeUint(Entry, VA - 0x8000);
+ // Local, global, TLS, reloc-only entries.
+ // If TLS entry has a corresponding dynamic relocations, leave it
+ // initialized by zero. Write down adjusted TLS symbol's values otherwise.
+ // To calculate the adjustments use offsets for thread-local storage.
+ // https://www.linux-mips.org/wiki/NPTL
+ for (const std::pair<GotEntry, size_t> &P : G.Local16)
+ Write(P.second, P.first.first, P.first.second);
+ // Write VA to the primary GOT only. For secondary GOTs that
+ // will be done by REL32 dynamic relocations.
+ if (&G == &Gots.front())
+ for (const std::pair<const Symbol *, size_t> &P : G.Global)
+ Write(P.second, P.first, 0);
+ for (const std::pair<Symbol *, size_t> &P : G.Relocs)
+ Write(P.second, P.first, 0);
+ for (const std::pair<Symbol *, size_t> &P : G.Tls)
+ Write(P.second, P.first, P.first->IsPreemptible ? 0 : -0x7000);
+ for (const std::pair<Symbol *, size_t> &P : G.DynTlsSymbols) {
+ if (P.first == nullptr && !Config->Pic)
+ Write(P.second, nullptr, 1);
+ else if (P.first && !P.first->IsPreemptible) {
+ Write(P.second, nullptr, 1);
+ Write(P.second + 1, P.first, -0x8000);
+ }
}
}
}
@@ -1234,7 +1397,10 @@ uint64_t DynamicReloc::getOffset() const {
int64_t DynamicReloc::computeAddend() const {
if (UseSymVA)
return Sym->getVA(Addend);
- return Addend;
+ if (!OutputSec)
+ return Addend;
+ // See the comment in the DynamicReloc ctor.
+ return getMipsPageAddr(OutputSec->Addr) + Addend;
}
uint32_t DynamicReloc::getSymIndex() const {
@@ -1288,17 +1454,6 @@ static void encodeDynamicReloc(typename ELFT::Rela *P,
if (Config->IsRela)
P->r_addend = Rel.computeAddend();
P->r_offset = Rel.getOffset();
- if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::MipsGot)
- // The MIPS GOT section contains dynamic relocations that correspond to TLS
- // entries. These entries are placed after the global and local sections of
- // the GOT. At the point when we create these relocations, the size of the
- // global and local sections is unknown, so the offset that we store in the
- // TLS entry's DynamicReloc is relative to the start of the TLS section of
- // the GOT, rather than being relative to the start of the GOT. This line of
- // code adds the size of the global and local sections to the virtual
- // address computed by getOffset() in order to adjust it into the TLS
- // section.
- P->r_offset += InX::MipsGot->getTlsOffset();
P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL);
}
@@ -1537,10 +1692,8 @@ static bool sortMipsSymbols(const SymbolTableEntry &L,
const SymbolTableEntry &R) {
// 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.Sym->IsInGlobalMipsGot;
- bool RIsInLocalGot = !R.Sym->IsInGlobalMipsGot;
- if (LIsInLocalGot || RIsInLocalGot)
- return !RIsInLocalGot;
+ if (!L.Sym->isInGot() || !R.Sym->isInGot())
+ return !L.Sym->isInGot();
return L.Sym->GotIndex < R.Sym->GotIndex;
}
@@ -2746,6 +2899,11 @@ template void PltSection::addEntry<ELF32BE>(Symbol &Sym);
template void PltSection::addEntry<ELF64LE>(Symbol &Sym);
template void PltSection::addEntry<ELF64BE>(Symbol &Sym);
+template void MipsGotSection::build<ELF32LE>();
+template void MipsGotSection::build<ELF32BE>();
+template void MipsGotSection::build<ELF64LE>();
+template void MipsGotSection::build<ELF64BE>();
+
template class elf::MipsAbiFlagsSection<ELF32LE>;
template class elf::MipsAbiFlagsSection<ELF32BE>;
template class elf::MipsAbiFlagsSection<ELF64LE>;
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index fc5ffa3f274..9776f2a32d0 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -178,12 +178,21 @@ public:
bool updateAllocSize() override;
void finalizeContents() override;
bool empty() const override;
- void addEntry(Symbol &Sym, int64_t Addend, RelExpr Expr);
- bool addDynTlsEntry(Symbol &Sym);
- bool addTlsIndex();
- uint64_t getPageEntryOffset(const Symbol &B, int64_t Addend) const;
- uint64_t getSymEntryOffset(const Symbol &B, int64_t Addend) const;
- uint64_t getGlobalDynOffset(const Symbol &B) const;
+
+ // Join separate GOTs built for each input file to generate
+ // primary and optional multiple secondary GOTs.
+ template <class ELFT> void build();
+
+ void addEntry(InputFile &File, Symbol &Sym, int64_t Addend, RelExpr Expr);
+ void addDynTlsEntry(InputFile &File, Symbol &Sym);
+ void addTlsIndex(InputFile &File);
+
+ uint64_t getPageEntryOffset(const InputFile &F, const Symbol &S,
+ int64_t Addend) const;
+ uint64_t getSymEntryOffset(const InputFile &F, const Symbol &S,
+ int64_t Addend) const;
+ uint64_t getGlobalDynOffset(const InputFile &F, const Symbol &S) const;
+ uint64_t getTlsIndexOffset(const InputFile &F) const;
// Returns the symbol which corresponds to the first entry of the global part
// of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic
@@ -195,13 +204,8 @@ public:
// the number of reserved entries.
unsigned getLocalEntriesNum() const;
- // Returns offset of TLS part of the MIPS GOT table. This part goes
- // after 'local' and 'global' entries.
- uint64_t getTlsOffset() const;
-
- uint32_t getTlsIndexOff() const { return TlsIndexOff; }
-
- uint64_t getGp() const;
+ // Return _gp value for primary GOT (nullptr) or particular input file.
+ uint64_t getGp(const InputFile *F = nullptr) const;
private:
// MIPS GOT consists of three parts: local, global and tls. Each part
@@ -240,32 +244,110 @@ private:
// addressing, but MIPS ABI requires that these entries be present in GOT.
// TLS entries:
// Entries created by TLS relocations.
+ //
+ // If the sum of local, global and tls entries is less than 64K only single
+ // got is enough. Otherwise, multi-got is created. Series of primary and
+ // multiple secondary GOTs have the following layout:
+ // - Primary GOT
+ // Header
+ // Local entries
+ // Global entries
+ // Relocation only entries
+ // TLS entries
+ //
+ // - Secondary GOT
+ // Local entries
+ // Global entries
+ // TLS entries
+ // ...
+ //
+ // All GOT entries required by relocations from a single input file entirely
+ // belong to either primary or one of secondary GOTs. To reference GOT entries
+ // each GOT has its own _gp value points to the "middle" of the GOT.
+ // In the code this value loaded to the register which is used for GOT access.
+ //
+ // MIPS 32 function's prologue:
+ // lui v0,0x0
+ // 0: R_MIPS_HI16 _gp_disp
+ // addiu v0,v0,0
+ // 4: R_MIPS_LO16 _gp_disp
+ //
+ // MIPS 64:
+ // lui at,0x0
+ // 14: R_MIPS_GPREL16 main
+ //
+ // Dynamic linker does not know anything about secondary GOTs and cannot
+ // use a regular MIPS mechanism for GOT entries initialization. So we have
+ // to use an approach accepted by other architectures and create dynamic
+ // relocations R_MIPS_REL32 to initialize global entries (and local in case
+ // of PIC code) in secondary GOTs. But ironically MIPS dynamic linker
+ // requires GOT entries and correspondingly ordered dynamic symbol table
+ // entries to deal with dynamic relocations. To handle this problem
+ // relocation-only section in the primary GOT contains entries for all
+ // symbols referenced in global parts of secondary GOTs. Although the sum
+ // of local and normal global entries of the primary got should be less
+ // than 64K, the size of the primary got (including relocation-only entries
+ // can be greater than 64K, because parts of the primary got that overflow
+ // the 64K limit are used only by the dynamic linker at dynamic link-time
+ // and not by 16-bit gp-relative addressing at run-time.
+ //
+ // For complete multi-GOT description see the following link
+ // https://dmz-portal.mips.com/wiki/MIPS_Multi_GOT
// Number of "Header" entries.
static const unsigned HeaderEntriesNum = 2;
- // Number of allocated "Page" entries.
- uint32_t PageEntriesNum = 0;
- // Map output sections referenced by MIPS GOT relocations
- // to the first index of "Page" entries allocated for this section.
- llvm::SmallMapVector<const OutputSection *, size_t, 16> PageIndexMap;
-
- typedef std::pair<const Symbol *, uint64_t> GotEntry;
- typedef std::vector<GotEntry> GotEntries;
- // Map from Symbol-Addend pair to the GOT index.
- llvm::DenseMap<GotEntry, size_t> EntryIndexMap;
- // Local entries (16-bit access).
- GotEntries LocalEntries;
- // Local entries (32-bit access).
- GotEntries LocalEntries32;
-
- // Normal and reloc-only global entries.
- GotEntries GlobalEntries;
-
- // TLS entries.
- std::vector<const Symbol *> TlsEntries;
- uint32_t TlsIndexOff = -1;
uint64_t Size = 0;
+
+ size_t LocalEntriesNum = 0;
+
+ // Symbol and addend.
+ typedef std::pair<Symbol *, int64_t> GotEntry;
+
+ struct FileGot {
+ InputFile *File = nullptr;
+ size_t StartIndex = 0;
+
+ struct PageBlock {
+ size_t FirstIndex = 0;
+ size_t Count = 0;
+ };
+
+ // Map output sections referenced by MIPS GOT relocations
+ // to the description (index/count) "page" entries allocated
+ // for this section.
+ llvm::SmallMapVector<const OutputSection *, PageBlock, 16> PagesMap;
+ // Maps from Symbol+Addend pair or just Symbol to the GOT entry index.
+ llvm::MapVector<GotEntry, size_t> Local16;
+ llvm::MapVector<GotEntry, size_t> Local32;
+ llvm::MapVector<Symbol *, size_t> Global;
+ llvm::MapVector<Symbol *, size_t> Relocs;
+ llvm::MapVector<Symbol *, size_t> Tls;
+ // Set of symbols referenced by dynamic TLS relocations.
+ llvm::MapVector<Symbol *, size_t> DynTlsSymbols;
+
+ // Total number of all entries.
+ size_t getEntriesNum() const;
+ // Number of "page" entries.
+ size_t getPageEntriesNum() const;
+ // Number of entries require 16-bit index to access.
+ size_t getIndexedEntriesNum() const;
+
+ bool isOverflow() const;
+ };
+
+ // Container of GOT created for each input file.
+ // After building a final series of GOTs this container
+ // holds primary and secondary GOT's.
+ std::vector<FileGot> Gots;
+
+ // Return (and create if necessary) `FileGot`.
+ FileGot &getGot(InputFile &F);
+
+ // Try to merge two GOTs. In case of success the `Dst` contains
+ // result of merging and the function returns true. In case of
+ // ovwerflow the `Dst` is unchanged and the function returns false.
+ bool tryMergeGots(FileGot & Dst, FileGot & Src, bool IsPrimary);
};
class GotPltSection final : public SyntheticSection {
@@ -318,7 +400,15 @@ public:
DynamicReloc(RelType Type, const InputSectionBase *InputSec,
uint64_t OffsetInSec, bool UseSymVA, Symbol *Sym, int64_t Addend)
: Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec),
- UseSymVA(UseSymVA), Addend(Addend) {}
+ UseSymVA(UseSymVA), Addend(Addend), OutputSec(nullptr) {}
+ // This constructor records dynamic relocation settings used by MIPS
+ // multi-GOT implementation. It's to relocate addresses of 64kb pages
+ // lie inside the output section.
+ DynamicReloc(RelType Type, const InputSectionBase *InputSec,
+ uint64_t OffsetInSec, const OutputSection *OutputSec,
+ int64_t Addend)
+ : Type(Type), Sym(nullptr), InputSec(InputSec), OffsetInSec(OffsetInSec),
+ UseSymVA(false), Addend(Addend), OutputSec(OutputSec) {}
uint64_t getOffset() const;
uint32_t getSymIndex() const;
@@ -341,6 +431,7 @@ private:
// plus the original addend as the final relocation addend.
bool UseSymVA;
int64_t Addend;
+ const OutputSection *OutputSec;
};
template <class ELFT> class DynamicSection final : public SyntheticSection {
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 998b0dcbe57..0a23d467922 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1611,6 +1611,9 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (errorCount())
return;
+ if (InX::MipsGot)
+ InX::MipsGot->build<ELFT>();
+
removeUnusedSyntheticSections();
sortSections();
diff --git a/lld/test/ELF/Inputs/mips-mgot-1.s b/lld/test/ELF/Inputs/mips-mgot-1.s
new file mode 100644
index 00000000000..def6e582115
--- /dev/null
+++ b/lld/test/ELF/Inputs/mips-mgot-1.s
@@ -0,0 +1,10 @@
+ .text
+ .global foo1
+foo1:
+ addiu $2, $2, %gottprel(tls0) # tls got entry
+ addiu $2, $2, %gottprel(tls1) # tls got entry
+
+ .section .tdata,"awT",%progbits
+ .global tls1
+tls1:
+ .word 0
diff --git a/lld/test/ELF/Inputs/mips-mgot-2.s b/lld/test/ELF/Inputs/mips-mgot-2.s
new file mode 100644
index 00000000000..4f6a92d36ff
--- /dev/null
+++ b/lld/test/ELF/Inputs/mips-mgot-2.s
@@ -0,0 +1,17 @@
+ .text
+ .global foo2
+foo2:
+ lw $2, %got(.data)($gp) # page entry
+ addi $2, $2, %lo(.data)
+ lw $2, %call16(foo0)($gp) # global entry
+ lw $2, %call16(foo2)($gp) # global entry
+ addiu $2, $2, %tlsgd(tls0) # tls gd entry
+ addiu $2, $2, %gottprel(tls0) # tls got entry
+
+ .data
+ .space 0x20000
+
+ .section .tdata,"awT",%progbits
+ .global tls2
+tls2:
+ .word 0
diff --git a/lld/test/ELF/mips-abs-got.s b/lld/test/ELF/mips-abs-got.s
new file mode 100644
index 00000000000..4964c855832
--- /dev/null
+++ b/lld/test/ELF/mips-abs-got.s
@@ -0,0 +1,36 @@
+# REQUIRES: mips
+
+# Check GOT relocations against absolute symbols.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -o %t.o %s
+# RUN: echo "SECTIONS { \
+# RUN: zero = 0; foo = 0x11004; bar = 0x22000; }" > %t.script
+# RUN: ld.lld --script %t.script -o %t.exe %t.o
+# RUN: llvm-readobj -mips-plt-got %t.exe | FileCheck %s
+
+# CHECK: Static GOT {
+# CHECK: Local entries [
+# CHECK-NEXT: Entry {
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Access: -32736
+# CHECK-NEXT: Initial: 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: Entry {
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Access: -32728
+# CHECK-NEXT: Initial: 0x10000
+# CHECK-NEXT: }
+# CHECK-NEXT: Entry {
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Access: -32720
+# CHECK-NEXT: Initial: 0x30000
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+# CHECK-NEXT: }
+
+ .text
+ nop
+ .reloc 0, R_MIPS_GOT_PAGE, 0
+ ld $v0, %got_page(zero)($gp)
+ ld $v0, %got_page(foo)($gp)
+ ld $v0, %got_page(bar+0x10008)($gp)
diff --git a/lld/test/ELF/mips-dynamic.s b/lld/test/ELF/mips-dynamic.s
index 820776be6ee..e1831221f41 100644
--- a/lld/test/ELF/mips-dynamic.s
+++ b/lld/test/ELF/mips-dynamic.s
@@ -99,8 +99,8 @@
# DSO: ]
# DSO: DynamicSymbols [
# DSO: Name: @
-# DSO: Name: __start@
# DSO: Name: _foo@
+# DSO: Name: __start@
# DSO: ]
# DSO: DynamicSection [
# DSO-NEXT: Tag Type Name/Value
diff --git a/lld/test/ELF/mips-got-script.s b/lld/test/ELF/mips-got-script.s
index da185846986..c4d827f428c 100644
--- a/lld/test/ELF/mips-got-script.s
+++ b/lld/test/ELF/mips-got-script.s
@@ -7,8 +7,8 @@
# REQUIRES: mips
-# CHECK: 0x7000000A MIPS_LOCAL_GOTNO 5
-# ^-- 2 * header + 3 local entries
+# CHECK: 0x7000000A MIPS_LOCAL_GOTNO 4
+# ^-- 2 * header + 2 local entries
# CHECK: Local entries [
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
@@ -22,12 +22,6 @@
# CHECK-NEXT: Initial: 0x10000
# ^-- loc2
# CHECK-NEXT: }
-# CHECK-NEXT: Entry {
-# CHECK-NEXT: Address:
-# CHECK-NEXT: Access: -32736
-# CHECK-NEXT: Initial: 0x20000
-# ^-- redundant
-# CHECK-NEXT: }
# CHECK-NEXT: ]
.text
diff --git a/lld/test/ELF/mips-got-weak.s b/lld/test/ELF/mips-got-weak.s
index e860bb482a2..d09e1269eb4 100644
--- a/lld/test/ELF/mips-got-weak.s
+++ b/lld/test/ELF/mips-got-weak.s
@@ -3,15 +3,15 @@
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
# RUN: ld.lld %t.o -shared -o %t1.so
# RUN: llvm-readobj -r -dt -dynamic-table -mips-plt-got %t1.so \
-# RUN: | FileCheck -check-prefix=NOSYM %s
+# RUN: | FileCheck -check-prefixes=CHECK,NOSYM %s
# RUN: ld.lld %t.o -shared -Bsymbolic -o %t2.so
# RUN: llvm-readobj -r -dt -dynamic-table -mips-plt-got %t2.so \
-# RUN: | FileCheck -check-prefix=SYM %s
+# RUN: | FileCheck -check-prefixes=CHECK,SYM %s
# REQUIRES: mips
-# NOSYM: Relocations [
-# NOSYM-NEXT: ]
+# CHECK: Relocations [
+# CHECK-NEXT: ]
# NOSYM: Symbol {
# NOSYM: Name: foo
@@ -22,17 +22,19 @@
# NOSYM-NEXT: Other: 0
# NOSYM-NEXT: Section: .data
# NOSYM-NEXT: }
-# NOSYM-NEXT: Symbol {
-# NOSYM-NEXT: Name: bar
-# NOSYM-NEXT: Value: 0x0
-# NOSYM-NEXT: Size: 0
-# NOSYM-NEXT: Binding: Weak
-# NOSYM-NEXT: Type: None
-# NOSYM-NEXT: Other: 0
-# NOSYM-NEXT: Section: Undefined
-# NOSYM-NEXT: }
-# NOSYM-NEXT: Symbol {
-# NOSYM-NEXT: Name: sym
+
+# CHECK: Symbol {
+# CHECK: Name: bar
+# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Size: 0
+# CHECK-NEXT: Binding: Weak
+# CHECK-NEXT: Type: None
+# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Section: Undefined
+# CHECK-NEXT: }
+
+# NOSYM: Symbol {
+# NOSYM: Name: sym
# NOSYM-NEXT: Value: 0x20004
# NOSYM-NEXT: Size: 0
# NOSYM-NEXT: Binding: Global
@@ -40,30 +42,48 @@
# NOSYM-NEXT: Other: 0
# NOSYM-NEXT: Section: .data
# NOSYM-NEXT: }
-# NOSYM-NEXT: ]
-# NOSYM: 0x70000011 MIPS_SYMTABNO 4
-# NOSYM-NEXT: 0x7000000A MIPS_LOCAL_GOTNO 2
-# NOSYM-NEXT: 0x70000013 MIPS_GOTSYM 0x1
+# CHECK: 0x70000011 MIPS_SYMTABNO 4
-# NOSYM: Primary GOT {
-# NOSYM-NEXT: Canonical gp value:
-# NOSYM-NEXT: Reserved entries [
-# NOSYM-NEXT: Entry {
-# NOSYM-NEXT: Address:
-# NOSYM-NEXT: Access: -32752
-# NOSYM-NEXT: Initial: 0x0
-# NOSYM-NEXT: Purpose: Lazy resolver
-# NOSYM-NEXT: }
-# NOSYM-NEXT: Entry {
-# NOSYM-NEXT: Address:
-# NOSYM-NEXT: Access: -32748
-# NOSYM-NEXT: Initial: 0x80000000
-# NOSYM-NEXT: Purpose: Module pointer (GNU extension)
-# NOSYM-NEXT: }
-# NOSYM-NEXT: ]
-# NOSYM-NEXT: Local entries [
+# SYM: 0x7000000A MIPS_LOCAL_GOTNO 4
+# SYM: 0x70000013 MIPS_GOTSYM 0x3
+
+# NOSYM: 0x7000000A MIPS_LOCAL_GOTNO 2
+# NOSYM: 0x70000013 MIPS_GOTSYM 0x1
+
+# CHECK: Primary GOT {
+# CHECK-NEXT: Canonical gp value:
+# CHECK-NEXT: Reserved entries [
+# CHECK: ]
+
+# SYM: Local entries [
+# SYM-NEXT: Entry {
+# SYM-NEXT: Address:
+# SYM-NEXT: Access: -32744
+# SYM-NEXT: Initial: 0x20000
+# SYM-NEXT: }
+# SYM-NEXT: Entry {
+# SYM-NEXT: Address:
+# SYM-NEXT: Access: -32740
+# SYM-NEXT: Initial: 0x20004
+# SYM-NEXT: }
+# SYM-NEXT: ]
+
+# NOSYM: Local entries [
# NOSYM-NEXT: ]
+
+# SYM-NEXT: Global entries [
+# SYM-NEXT: Entry {
+# SYM-NEXT: Address:
+# SYM-NEXT: Access: -32736
+# SYM-NEXT: Initial: 0x0
+# SYM-NEXT: Value: 0x0
+# SYM-NEXT: Type: None
+# SYM-NEXT: Section: Undefined
+# SYM-NEXT: Name: bar
+# SYM-NEXT: }
+# SYM-NEXT: ]
+
# NOSYM-NEXT: Global entries [
# NOSYM-NEXT: Entry {
# NOSYM-NEXT: Address:
@@ -93,68 +113,9 @@
# NOSYM-NEXT: Name: sym
# NOSYM-NEXT: }
# NOSYM-NEXT: ]
-# NOSYM-NEXT: Number of TLS and multi-GOT entries: 0
-# NOSYM-NEXT: }
-
-# SYM: Relocations [
-# SYM-NEXT: ]
-
-# SYM: Symbol {
-# SYM: Name: bar
-# SYM-NEXT: Value: 0x0
-# SYM-NEXT: Size: 0
-# SYM-NEXT: Binding: Weak
-# SYM-NEXT: Type: None
-# SYM-NEXT: Other: 0
-# SYM-NEXT: Section: Undefined
-# SYM-NEXT: }
-# SYM-NEXT: ]
-
-# SYM: 0x70000011 MIPS_SYMTABNO 4
-# SYM-NEXT: 0x7000000A MIPS_LOCAL_GOTNO 4
-# SYM-NEXT: 0x70000013 MIPS_GOTSYM 0x3
-
-# SYM: Primary GOT {
-# SYM-NEXT: Canonical gp value:
-# SYM-NEXT: Reserved entries [
-# SYM-NEXT: Entry {
-# SYM-NEXT: Address:
-# SYM-NEXT: Access: -32752
-# SYM-NEXT: Initial: 0x0
-# SYM-NEXT: Purpose: Lazy resolver
-# SYM-NEXT: }
-# SYM-NEXT: Entry {
-# SYM-NEXT: Address:
-# SYM-NEXT: Access: -32748
-# SYM-NEXT: Initial: 0x80000000
-# SYM-NEXT: Purpose: Module pointer (GNU extension)
-# SYM-NEXT: }
-# SYM-NEXT: ]
-# SYM-NEXT: Local entries [
-# SYM-NEXT: Entry {
-# SYM-NEXT: Address:
-# SYM-NEXT: Access: -32744
-# SYM-NEXT: Initial: 0x20000
-# SYM-NEXT: }
-# SYM-NEXT: Entry {
-# SYM-NEXT: Address:
-# SYM-NEXT: Access: -32740
-# SYM-NEXT: Initial: 0x20004
-# SYM-NEXT: }
-# SYM-NEXT: ]
-# SYM-NEXT: Global entries [
-# SYM-NEXT: Entry {
-# SYM-NEXT: Address:
-# SYM-NEXT: Access: -32736
-# SYM-NEXT: Initial: 0x0
-# SYM-NEXT: Value: 0x0
-# SYM-NEXT: Type: None
-# SYM-NEXT: Section: Undefined
-# SYM-NEXT: Name: bar
-# SYM-NEXT: }
-# SYM-NEXT: ]
-# SYM-NEXT: Number of TLS and multi-GOT entries: 0
-# SYM-NEXT: }
+
+# CHECK: Number of TLS and multi-GOT entries: 0
+# CHECK-NEXT: }
.text
.global sym
diff --git a/lld/test/ELF/mips-mgot.s b/lld/test/ELF/mips-mgot.s
new file mode 100644
index 00000000000..ca9703dbee1
--- /dev/null
+++ b/lld/test/ELF/mips-mgot.s
@@ -0,0 +1,129 @@
+# Check MIPS multi-GOT layout.
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t0.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: %p/Inputs/mips-mgot-1.s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
+# RUN: %p/Inputs/mips-mgot-2.s -o %t2.o
+# RUN: ld.lld -shared -mips-got-size 52 %t0.o %t1.o %t2.o -o %t.so
+# RUN: llvm-objdump -s -section=.got -t %t.so | FileCheck %s
+# RUN: llvm-readobj -r -dt -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s
+
+# REQUIRES: mips
+
+# CHECK: Contents of section .got:
+# CHECK-NEXT: 60000 00000000 80000000 00010000 00010030
+# CHECK-NEXT: 60010 00020000 00030000 00040000 00050000
+# CHECK-NEXT: 60020 00060000 00070000 00000000 00000000
+# CHECK-NEXT: 60030 00000004 00000000 00000000 00000000
+# CHECK-NEXT: 60040 00000000 00020000 00030000 00040000
+# CHECK-NEXT: 60050 00050000 00060000 00070000 00000000
+# CHECK-NEXT: 60060 00000000 00000000 00000000 00000000
+
+# CHECK: SYMBOL TABLE:
+# CHECK: 00000000 l .tdata 00000000 loc0
+# CHECK: 00010000 .text 00000000 foo0
+# CHECK: 00000000 g .tdata 00000000 tls0
+# CHECK: 00010020 .text 00000000 foo1
+# CHECK: 00000004 g .tdata 00000000 tls1
+# CHECK: 00010030 .text 00000000 foo2
+# CHECK: 00000008 g .tdata 00000000 tls2
+
+# GOT: Relocations [
+# GOT-NEXT: Section (7) .rel.dyn {
+# GOT-NEXT: 0x60010 R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x60014 R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x60018 R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x6001C R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x60020 R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x60024 R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x60044 R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x60048 R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x6004C R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x60050 R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x60054 R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x60058 R_MIPS_REL32 - 0x0
+# GOT-NEXT: 0x60028 R_MIPS_REL32 foo0 0x0
+# GOT-NEXT: 0x6005C R_MIPS_REL32 foo0 0x0
+# GOT-NEXT: 0x60060 R_MIPS_REL32 foo2 0x0
+# GOT-NEXT: 0x6003C R_MIPS_TLS_DTPMOD32 - 0x0
+# GOT-NEXT: 0x60030 R_MIPS_TLS_TPREL32 tls1 0x0
+# GOT-NEXT: 0x6002C R_MIPS_TLS_TPREL32 tls0 0x0
+# GOT-NEXT: 0x60034 R_MIPS_TLS_DTPMOD32 tls0 0x0
+# GOT-NEXT: 0x60038 R_MIPS_TLS_DTPREL32 tls0 0x0
+# GOT-NEXT: 0x60064 R_MIPS_TLS_TPREL32 tls0 0x0
+# GOT-NEXT: 0x60068 R_MIPS_TLS_DTPMOD32 tls0 0x0
+# GOT-NEXT: 0x6006C R_MIPS_TLS_DTPREL32 tls0 0x0
+# GOT-NEXT: }
+# GOT-NEXT: ]
+
+# GOT: DynamicSymbols [
+# GOT: Symbol {
+# GOT: Name: foo0
+# GOT-NEXT: Value: 0x10000
+# GOT: }
+# GOT-NEXT: Symbol {
+# GOT-NEXT: Name: foo2
+# GOT-NEXT: Value: 0x10030
+# GOT: }
+# GOT-NEXT: ]
+
+# GOT: Primary GOT {
+# GOT-NEXT: Canonical gp value: 0x67FF0
+# GOT-NEXT: Reserved entries [
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address:
+# GOT-NEXT: Access: -32752
+# GOT-NEXT: Initial: 0x0
+# GOT-NEXT: Purpose: Lazy resolver
+# GOT-NEXT: }
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address:
+# GOT-NEXT: Access: -32748
+# GOT-NEXT: Initial: 0x80000000
+# GOT-NEXT: Purpose: Module pointer (GNU extension)
+# GOT-NEXT: }
+# GOT-NEXT: ]
+# GOT-NEXT: Local entries [
+# GOT-NEXT: ]
+# GOT-NEXT: Global entries [
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address:
+# GOT-NEXT: Access: -32744
+# GOT-NEXT: Initial: 0x10000
+# GOT-NEXT: Value: 0x10000
+# GOT-NEXT: Type: None
+# GOT-NEXT: Section: .text
+# GOT-NEXT: Name: foo0
+# GOT-NEXT: }
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address:
+# GOT-NEXT: Access: -32740
+# GOT-NEXT: Initial: 0x10030
+# GOT-NEXT: Value: 0x10030
+# GOT-NEXT: Type: None
+# GOT-NEXT: Section: .text
+# GOT-NEXT: Name: foo2
+# GOT-NEXT: }
+# GOT-NEXT: ]
+# GOT-NEXT: Number of TLS and multi-GOT entries: 24
+# GOT-NEXT: }
+
+ .text
+ .global foo0
+foo0:
+ lw $2, %got(.data)($gp) # page entry
+ addi $2, $2, %lo(.data)
+ lw $2, %call16(foo0)($gp) # global entry
+ addiu $2, $2, %tlsgd(tls0) # tls gd entry
+ addiu $2, $2, %gottprel(tls0) # tls got entry
+ addiu $2, $2, %tlsldm(loc0) # tls ld entry
+
+ .data
+ .space 0x20000
+
+ .section .tdata,"awT",%progbits
+ .global tls0
+tls0:
+loc0:
+ .word 0
diff --git a/lld/test/ELF/mips-plt-copy.s b/lld/test/ELF/mips-plt-copy.s
index 58883d88456..26192163e75 100644
--- a/lld/test/ELF/mips-plt-copy.s
+++ b/lld/test/ELF/mips-plt-copy.s
@@ -12,12 +12,12 @@
# CHECK: Relocations [
# CHECK-NEXT: Section ({{.*}}) .rel.dyn {
-# CHECK-NEXT: 0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0
-# CHECK-NEXT: 0x{{[0-9A-F]+}} R_MIPS_COPY data1 0x0
+# CHECK-DAG: 0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0
+# CHECK-DAG: 0x{{[0-9A-F]+}} R_MIPS_COPY data1 0x0
# CHECK-NEXT: }
# CHECK-NEXT: Section ({{.*}}) .rel.plt {
-# CHECK-NEXT: 0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo0 0x0
-# CHECK-NEXT: 0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo1 0x0
+# CHECK-DAG: 0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo0 0x0
+# CHECK-DAG: 0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo1 0x0
# CHECK-NEXT: }
# CHECK-NEXT: ]
diff --git a/lld/test/ELF/mips-sto-plt.s b/lld/test/ELF/mips-sto-plt.s
index bd8de416680..56a7c055b6a 100644
--- a/lld/test/ELF/mips-sto-plt.s
+++ b/lld/test/ELF/mips-sto-plt.s
@@ -10,23 +10,23 @@
# REQUIRES: mips
# CHECK: Symbol {
-# CHECK: Name: foo0@
-# CHECK-NEXT: Value: 0x0
+# CHECK: Name: foo1@
+# CHECK-NEXT: Value: 0x[[FOO1:[0-9A-F]+]]
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Global
# CHECK-NEXT: Type: Function
-# CHECK-NEXT: Other: 0
+# CHECK-NEXT: Other [ (0x8)
+# CHECK-NEXT: STO_MIPS_PLT
+# CHECK-NEXT: ]
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: }
# CHECK: Symbol {
-# CHECK: Name: foo1@
-# CHECK-NEXT: Value: 0x20050
+# CHECK: Name: foo0@
+# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Global
# CHECK-NEXT: Type: Function
-# CHECK-NEXT: Other [ (0x8)
-# CHECK-NEXT: STO_MIPS_PLT
-# CHECK-NEXT: ]
+# CHECK-NEXT: Other: 0
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: }
@@ -48,7 +48,7 @@
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
# CHECK-NEXT: Initial:
-# CHECK-NEXT: Value: 0x20050
+# CHECK-NEXT: Value: 0x[[FOO1]]
# CHECK-NEXT: Type: Function
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: Name: foo1
diff --git a/lld/test/ELF/mips-tls-64.s b/lld/test/ELF/mips-tls-64.s
index 67ff13451d1..7d191f963e4 100644
--- a/lld/test/ELF/mips-tls-64.s
+++ b/lld/test/ELF/mips-tls-64.s
@@ -16,18 +16,18 @@
# REQUIRES: mips
# DIS: __start:
-# DIS-NEXT: 20000: 24 62 80 20 addiu $2, $3, -32736
-# DIS-NEXT: 20004: 24 62 80 30 addiu $2, $3, -32720
-# DIS-NEXT: 20008: 24 62 80 38 addiu $2, $3, -32712
-# DIS-NEXT: 2000c: 24 62 80 48 addiu $2, $3, -32696
-# DIS-NEXT: 20010: 24 62 80 58 addiu $2, $3, -32680
+# DIS-NEXT: 20000: 24 62 80 30 addiu $2, $3, -32720
+# DIS-NEXT: 20004: 24 62 80 20 addiu $2, $3, -32736
+# DIS-NEXT: 20008: 24 62 80 40 addiu $2, $3, -32704
+# DIS-NEXT: 2000c: 24 62 80 50 addiu $2, $3, -32688
+# DIS-NEXT: 20010: 24 62 80 28 addiu $2, $3, -32728
# DIS: Contents of section .got:
# DIS-NEXT: 30010 00000000 00000000 80000000 00000000
-# DIS-NEXT: 30020 00000000 00000000 00000000 00000000
-# DIS-NEXT: 30030 00000000 00000000 00000000 00000001
-# DIS-NEXT: 30040 00000000 00000000 00000000 00000001
-# DIS-NEXT: 30050 ffffffff ffff8004 ffffffff ffff9004
+# DIS-NEXT: 30020 00000000 00000000 ffffffff ffff9004
+# DIS-NEXT: 30030 00000000 00000000 00000000 00000000
+# DIS-NEXT: 30040 00000000 00000001 00000000 00000000
+# DIS-NEXT: 30050 00000000 00000001 ffffffff ffff8004
# DIS: 0000000000000000 l .tdata 00000000 loc
# DIS: 0000000000000004 g .tdata 00000000 bar
@@ -35,9 +35,9 @@
# CHECK: Relocations [
# CHECK-NEXT: Section (7) .rel.dyn {
-# CHECK-NEXT: 0x30020 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
-# CHECK-NEXT: 0x30028 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
-# CHECK-NEXT: 0x30030 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# CHECK-NEXT: 0x30020 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# CHECK-NEXT: 0x30030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# CHECK-NEXT: 0x30038 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NEXT: Primary GOT {
@@ -49,31 +49,31 @@
# CHECK-NEXT: Global entries [
# CHECK-NEXT: ]
# CHECK-NEXT: Number of TLS and multi-GOT entries: 8
-# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 foo
-# ^-- -32728 R_MIPS_TLS_DTPREL64 foo
-# ^-- -32720 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 foo
-# ^-- -32712 R_MIPS_TLS_LDM 1 loc
-# ^-- -32704 0 loc
-# ^-- -32696 R_MIPS_TLS_GD 1 bar
-# ^-- -32688 VA - 0x8000 bar
-# ^-- -32680 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar
+# ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 foo
+# ^-- -32728 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar
+# ^-- -32720 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 foo
+# ^-- -32712 R_MIPS_TLS_DTPREL64 foo
+# ^-- -32704 R_MIPS_TLS_LDM 1 loc
+# ^-- -32696 0 loc
+# ^-- -32688 R_MIPS_TLS_GD 1 bar
+# ^-- -32680 VA - 0x8000 bar
# DIS-SO: Contents of section .got:
# DIS-SO-NEXT: 20000 00000000 00000000 80000000 00000000
-# DIS-SO-NEXT: 20010 00000000 00000000 00000000 00000000
+# DIS-SO-NEXT: 20010 00000000 00000000 00000000 00000004
# DIS-SO-NEXT: 20020 00000000 00000000 00000000 00000000
# DIS-SO-NEXT: 20030 00000000 00000000 00000000 00000000
# DIS-SO-NEXT: 20040 00000000 00000000 00000000 00000000
# SO: Relocations [
# SO-NEXT: Section (7) .rel.dyn {
-# SO-NEXT: 0x20028 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0
-# SO-NEXT: 0x20038 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
-# SO-NEXT: 0x20040 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
-# SO-NEXT: 0x20048 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
-# SO-NEXT: 0x20010 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
-# SO-NEXT: 0x20018 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
-# SO-NEXT: 0x20020 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT: 0x20030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0
+# SO-NEXT: 0x20010 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT: 0x20020 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT: 0x20028 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0
+# SO-NEXT: 0x20018 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
+# SO-NEXT: 0x20040 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
+# SO-NEXT: 0x20048 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0
# SO-NEXT: }
# SO-NEXT: ]
# SO-NEXT: Primary GOT {
@@ -85,14 +85,14 @@
# SO-NEXT: Global entries [
# SO-NEXT: ]
# SO-NEXT: Number of TLS and multi-GOT entries: 8
-# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 foo
-# ^-- -32728 R_MIPS_TLS_DTPREL64 foo
-# ^-- -32720 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 foo
-# ^-- -32712 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD64 loc
-# ^-- -32704 0 loc
-# ^-- -32696 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 bar
-# ^-- -32688 R_MIPS_TLS_DTPREL64 bar
-# ^-- -32680 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 bar
+# ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 foo
+# ^-- -32728 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 bar
+# ^-- -32720 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 foo
+# ^-- -32712 R_MIPS_TLS_DTPREL64 foo
+# ^-- -32704 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD64 loc
+# ^-- -32696 0 loc
+# ^-- -32688 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 bar
+# ^-- -32680 R_MIPS_TLS_DTPREL64 bar
.text
.global __start
diff --git a/lld/test/ELF/mips-tls-static.s b/lld/test/ELF/mips-tls-static.s
index 84b56cb4224..a880159338a 100644
--- a/lld/test/ELF/mips-tls-static.s
+++ b/lld/test/ELF/mips-tls-static.s
@@ -10,8 +10,8 @@
# CHECK: Contents of section .data:
# CHECK-NEXT: 30000 0002000c ffff8004 ffff9004
# CHECK: Contents of section .got:
-# CHECK-NEXT: 30010 00000000 80000000 00000001 ffff8000
-# CHECK-NEXT: 30020 00000001 00000000 ffff9000
+# CHECK-NEXT: 30010 00000000 80000000 ffff9000 00000001
+# CHECK-NEXT: 30020 ffff8000 00000001 00000000
#
# CHECK: SYMBOL TABLE:
# CHECK: 0002000c .text 00000000 __tls_get_addr
diff --git a/lld/test/ELF/mips-tls.s b/lld/test/ELF/mips-tls.s
index b64f8db7573..a8bd9235bc6 100644
--- a/lld/test/ELF/mips-tls.s
+++ b/lld/test/ELF/mips-tls.s
@@ -16,16 +16,16 @@
# REQUIRES: mips
# DIS: __start:
-# DIS-NEXT: 20000: 24 62 80 18 addiu $2, $3, -32744
-# DIS-NEXT: 20004: 24 62 80 20 addiu $2, $3, -32736
-# DIS-NEXT: 20008: 24 62 80 24 addiu $2, $3, -32732
-# DIS-NEXT: 2000c: 24 62 80 2c addiu $2, $3, -32724
-# DIS-NEXT: 20010: 24 62 80 34 addiu $2, $3, -32716
+# DIS-NEXT: 20000: 24 62 80 20 addiu $2, $3, -32736
+# DIS-NEXT: 20004: 24 62 80 18 addiu $2, $3, -32744
+# DIS-NEXT: 20008: 24 62 80 28 addiu $2, $3, -32728
+# DIS-NEXT: 2000c: 24 62 80 30 addiu $2, $3, -32720
+# DIS-NEXT: 20010: 24 62 80 1c addiu $2, $3, -32740
# DIS: Contents of section .got:
-# DIS-NEXT: 30010 00000000 80000000 00000000 00000000
-# DIS-NEXT: 30020 00000000 00000001 00000000 00000001
-# DIS-NEXT: 30030 ffff8004 ffff9004
+# DIS-NEXT: 30010 00000000 80000000 00000000 ffff9004
+# DIS-NEXT: 30020 00000000 00000000 00000001 00000000
+# DIS-NEXT: 30030 00000001 ffff8004
# DIS: 00000000 l .tdata 00000000 loc
# DIS: 00000004 g .tdata 00000000 bar
@@ -33,9 +33,9 @@
# CHECK: Relocations [
# CHECK-NEXT: Section (7) .rel.dyn {
-# CHECK-NEXT: 0x30018 R_MIPS_TLS_DTPMOD32 foo 0x0
-# CHECK-NEXT: 0x3001C R_MIPS_TLS_DTPREL32 foo 0x0
-# CHECK-NEXT: 0x30020 R_MIPS_TLS_TPREL32 foo 0x0
+# CHECK-NEXT: 0x30018 R_MIPS_TLS_TPREL32 foo 0x0
+# CHECK-NEXT: 0x30020 R_MIPS_TLS_DTPMOD32 foo 0x0
+# CHECK-NEXT: 0x30024 R_MIPS_TLS_DTPREL32 foo 0x0
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NEXT: Primary GOT {
@@ -47,29 +47,29 @@
# CHECK-NEXT: Global entries [
# CHECK-NEXT: ]
# CHECK-NEXT: Number of TLS and multi-GOT entries: 8
-# ^-- -32744 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo
-# ^-- -32740 R_MIPS_TLS_DTPREL32 foo
-# ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo
-# ^-- -32732 R_MIPS_TLS_LDM 1 loc
-# ^-- -32728 0 loc
-# ^-- -32724 R_MIPS_TLS_GD 1 bar
-# ^-- -32720 VA - 0x8000 bar
-# ^-- -32716 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar
+# ^-- -32744 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo
+# ^-- -32740 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar
+# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo
+# ^-- -32732 R_MIPS_TLS_DTPREL32 foo
+# ^-- -32728 R_MIPS_TLS_LDM 1 loc
+# ^-- -32724 0 loc
+# ^-- -32720 R_MIPS_TLS_GD 1 bar
+# ^-- -32716 VA - 0x8000 bar
# DIS-SO: Contents of section .got:
-# DIS-SO-NEXT: 20000 00000000 80000000 00000000 00000000
+# DIS-SO-NEXT: 20000 00000000 80000000 00000000 00000004
# DIS-SO-NEXT: 20010 00000000 00000000 00000000 00000000
# DIS-SO-NEXT: 20020 00000000 00000000
# SO: Relocations [
# SO-NEXT: Section (7) .rel.dyn {
-# SO-NEXT: 0x20014 R_MIPS_TLS_DTPMOD32 - 0x0
-# SO-NEXT: 0x2001C R_MIPS_TLS_DTPMOD32 bar 0x0
-# SO-NEXT: 0x20020 R_MIPS_TLS_DTPREL32 bar 0x0
-# SO-NEXT: 0x20024 R_MIPS_TLS_TPREL32 bar 0x0
-# SO-NEXT: 0x20008 R_MIPS_TLS_DTPMOD32 foo 0x0
-# SO-NEXT: 0x2000C R_MIPS_TLS_DTPREL32 foo 0x0
-# SO-NEXT: 0x20010 R_MIPS_TLS_TPREL32 foo 0x0
+# SO-NEXT: 0x20018 R_MIPS_TLS_DTPMOD32 - 0x0
+# SO-NEXT: 0x20008 R_MIPS_TLS_TPREL32 foo 0x0
+# SO-NEXT: 0x20010 R_MIPS_TLS_DTPMOD32 foo 0x0
+# SO-NEXT: 0x20014 R_MIPS_TLS_DTPREL32 foo 0x0
+# SO-NEXT: 0x2000C R_MIPS_TLS_TPREL32 bar 0x0
+# SO-NEXT: 0x20020 R_MIPS_TLS_DTPMOD32 bar 0x0
+# SO-NEXT: 0x20024 R_MIPS_TLS_DTPREL32 bar 0x0
# SO-NEXT: }
# SO-NEXT: ]
# SO-NEXT: Primary GOT {
@@ -81,14 +81,14 @@
# SO-NEXT: Global entries [
# SO-NEXT: ]
# SO-NEXT: Number of TLS and multi-GOT entries: 8
-# ^-- -32744 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo
-# ^-- -32740 R_MIPS_TLS_DTPREL32 foo
-# ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo
-# ^-- -32732 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD32 loc
-# ^-- -32728 0 loc
-# ^-- -32724 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 bar
-# ^-- -32720 R_MIPS_TLS_DTPREL32 bar
-# ^-- -32716 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 bar
+# ^-- -32744 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo
+# ^-- -32740 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 bar
+# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo
+# ^-- -32732 R_MIPS_TLS_DTPREL32 foo
+# ^-- -32728 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD32 loc
+# ^-- -32724 0 loc
+# ^-- -32720 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 bar
+# ^-- -32716 R_MIPS_TLS_DTPREL32 bar
.text
.global __start
OpenPOWER on IntegriCloud