summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/InputSection.cpp12
-rw-r--r--lld/ELF/OutputSections.cpp211
-rw-r--r--lld/ELF/OutputSections.h24
-rw-r--r--lld/ELF/Relocations.cpp32
-rw-r--r--lld/ELF/Relocations.h2
-rw-r--r--lld/ELF/Symbols.cpp13
-rw-r--r--lld/ELF/Symbols.h3
-rw-r--r--lld/ELF/Target.cpp4
-rw-r--r--lld/test/ELF/mips-64-disp.s89
-rw-r--r--lld/test/ELF/mips-64-got.s21
-rw-r--r--lld/test/ELF/mips-dynamic.s2
-rw-r--r--lld/test/ELF/mips-got16.s12
-rw-r--r--lld/test/ELF/mips-plt-copy.s2
-rw-r--r--lld/test/ELF/mips-sto-plt.s16
14 files changed, 291 insertions, 152 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 568b99ba8b9..f02106a4ce7 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -215,13 +215,11 @@ getSymVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
// should be initialized by 'page address'. This address is high 16-bits
// of sum the symbol's value and the addend.
return Out<ELFT>::Got->getMipsLocalPageOffset(Body.getVA<ELFT>(A));
- case R_MIPS_GOT_LOCAL:
- // 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<ELFT>::Got->getMipsLocalEntryOffset(Body.getVA<ELFT>(A));
+ case R_MIPS_GOT_OFF:
+ // 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 Out<ELFT>::Got->getMipsGotOffset(Body, A);
case R_PPC_OPD: {
uint64_t SymVA = Body.getVA<ELFT>(A);
// If we have an undefined weak symbol, we might get here with a symbol
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index 40cb4263e87..1f6151819aa 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -92,58 +92,67 @@ GotSection<ELFT>::GotSection()
this->Header.sh_addralign = sizeof(uintX_t);
}
-template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody &Sym) {
- if (Config->EMachine == EM_MIPS) {
- // 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
- 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;
- }
- }
+template <class ELFT>
+void GotSection<ELFT>::addEntry(SymbolBody &Sym) {
Sym.GotIndex = Entries.size();
Entries.push_back(&Sym);
}
+template <class ELFT>
+void GotSection<ELFT>::addMipsEntry(SymbolBody &Sym, uintX_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
+ 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.
+ auto *OutSec = cast<DefinedRegular<ELFT>>(&Sym)->Section->OutSec;
+ MipsOutSections.insert(OutSec);
+ return;
+ }
+ auto AddEntry = [&](SymbolBody &S, uintX_t A, MipsGotEntries &Items) {
+ if (S.isInGot() && !A)
+ return;
+ size_t NewIndex = Items.size();
+ if (!MipsGotMap.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, MipsGlobal);
+ Sym.IsInGlobalMipsGot = true;
+ } else
+ AddEntry(Sym, Addend, MipsLocal);
+}
+
template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) {
if (Sym.GlobalDynIndex != -1U)
return false;
@@ -170,22 +179,33 @@ typename GotSection<ELFT>::uintX_t
GotSection<ELFT>::getMipsLocalPageOffset(uintX_t EntryValue) {
// Initialize the entry by the %hi(EntryValue) expression
// but without right-shifting.
- return getMipsLocalEntryOffset((EntryValue + 0x8000) & ~0xffff);
-}
-
-template <class ELFT>
-typename GotSection<ELFT>::uintX_t
-GotSection<ELFT>::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;
auto P = MipsLocalGotPos.insert(std::make_pair(EntryValue, NewIndex));
- assert(!P.second || MipsLocalGotPos.size() <= MipsLocalEntries);
+ assert(!P.second || MipsLocalGotPos.size() <= MipsPageEntries);
return (uintX_t)P.first->second * sizeof(uintX_t) - MipsGPOffset;
}
template <class ELFT>
typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const {
+ uintX_t Off = MipsPageEntries;
+ if (B.IsInGlobalMipsGot)
+ Off += MipsLocal.size() + B.GotIndex;
+ else if (B.isInGot())
+ Off += B.GotIndex;
+ else {
+ auto It = MipsGotMap.find({&B, Addend});
+ assert(It != MipsGotMap.end());
+ Off += It->second;
+ }
+ return Off * sizeof(uintX_t) - MipsGPOffset;
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t
GotSection<ELFT>::getGlobalDynAddr(const SymbolBody &B) const {
return this->getVA() + B.GlobalDynIndex * sizeof(uintX_t);
}
@@ -198,12 +218,12 @@ GotSection<ELFT>::getGlobalDynOffset(const SymbolBody &B) const {
template <class ELFT>
const SymbolBody *GotSection<ELFT>::getMipsFirstGlobalEntry() const {
- return Entries.empty() ? nullptr : Entries.front();
+ return MipsGlobal.empty() ? nullptr : MipsGlobal.front().first;
}
template <class ELFT>
unsigned GotSection<ELFT>::getMipsLocalEntriesNum() const {
- return MipsLocalEntries;
+ return MipsPageEntries + MipsLocal.size();
}
template <class ELFT> void GotSection<ELFT>::finalize() {
@@ -211,55 +231,62 @@ template <class ELFT> void GotSection<ELFT>::finalize() {
if (Config->EMachine == EM_MIPS) {
// Take into account MIPS GOT header.
// See comment in the GotSection::writeTo.
- MipsLocalEntries += 2;
+ MipsPageEntries += 2;
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;
+ MipsPageEntries += (OutSec->getSize() + 0x8000 + 0xfffe) / 0xffff;
}
- EntriesNum += MipsLocalEntries;
+ EntriesNum += MipsPageEntries + MipsLocal.size() + MipsGlobal.size();
}
this->Header.sh_size = EntriesNum * sizeof(uintX_t);
}
-template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
- if (Config->EMachine == EM_MIPS) {
- // Set the MSB of the second GOT slot. This is not required by any
- // MIPS ABI documentation, though.
- //
- // There is a comment in glibc saying that "The MSB of got[1] of a
- // gnu object is set to identify gnu objects," and in GNU gold it
- // says "the second entry will be used by some runtime loaders".
- // But how this field is being used is unclear.
- //
- // We are not really willing to mimic other linkers behaviors
- // without understanding why they do that, but because all files
- // generated by GNU tools have this special GOT value, and because
- // we've been doing this for years, it is probably a safe bet to
- // keep doing this for now. We really need to revisit this to see
- // if we had to do this.
- auto *P = reinterpret_cast<typename ELFT::Off *>(Buf);
- P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31);
- for (std::pair<uintX_t, size_t> &L : MipsLocalGotPos) {
- uint8_t *Entry = Buf + L.second * sizeof(uintX_t);
- write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, L.first);
- }
- Buf += MipsLocalEntries * sizeof(uintX_t);
+template <class ELFT> void GotSection<ELFT>::writeMipsGot(uint8_t *&Buf) {
+ // Set the MSB of the second GOT slot. This is not required by any
+ // MIPS ABI documentation, though.
+ //
+ // There is a comment in glibc saying that "The MSB of got[1] of a
+ // gnu object is set to identify gnu objects," and in GNU gold it
+ // says "the second entry will be used by some runtime loaders".
+ // But how this field is being used is unclear.
+ //
+ // We are not really willing to mimic other linkers behaviors
+ // without understanding why they do that, but because all files
+ // generated by GNU tools have this special GOT value, and because
+ // we've been doing this for years, it is probably a safe bet to
+ // keep doing this for now. We really need to revisit this to see
+ // if we had to do this.
+ auto *P = reinterpret_cast<typename ELFT::Off *>(Buf);
+ P[1] = uintX_t(1) << (ELFT::Is64Bits ? 63 : 31);
+ // Write 'page address' entries to the local part of the GOT.
+ for (std::pair<uintX_t, size_t> &L : MipsLocalGotPos) {
+ uint8_t *Entry = Buf + L.second * sizeof(uintX_t);
+ write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, L.first);
}
+ Buf += MipsPageEntries * sizeof(uintX_t);
+ auto AddEntry = [&](const MipsGotEntry &SA) {
+ uint8_t *Entry = Buf;
+ Buf += sizeof(uintX_t);
+ uintX_t VA = SA.first->template getVA<ELFT>(SA.second);
+ write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA);
+ };
+ std::for_each(std::begin(MipsLocal), std::end(MipsLocal), AddEntry);
+ std::for_each(std::begin(MipsGlobal), std::end(MipsGlobal), AddEntry);
+}
+
+template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
+ if (Config->EMachine == EM_MIPS)
+ writeMipsGot(Buf);
for (const SymbolBody *B : Entries) {
uint8_t *Entry = Buf;
Buf += sizeof(uintX_t);
if (!B)
continue;
- // MIPS has special rules to fill up GOT entries.
- // 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
- // As the first approach, we can just store addresses for all symbols.
- if (Config->EMachine != EM_MIPS && B->isPreemptible())
+ if (B->isPreemptible())
continue; // The dynamic linker will take care of it.
uintX_t VA = B->getVA<ELFT>();
write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA);
@@ -1249,10 +1276,8 @@ static bool sortMipsSymbols(const std::pair<SymbolBody *, unsigned> &L,
const std::pair<SymbolBody *, unsigned> &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.first->isInGot() || !L.first->isPreemptible();
- bool RIsInLocalGot = !R.first->isInGot() || !R.first->isPreemptible();
- if (LIsInLocalGot || RIsInLocalGot)
- return !RIsInLocalGot;
+ if (!L.first->IsInGlobalMipsGot || !R.first->IsInGlobalMipsGot)
+ return !L.first->IsInGlobalMipsGot;
return L.first->GotIndex < R.first->GotIndex;
}
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index 89665a063bc..4b05e71dd4e 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -11,6 +11,7 @@
#define LLD_ELF_OUTPUT_SECTIONS_H
#include "Config.h"
+#include "Relocations.h"
#include "lld/Core/LLVM.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -113,11 +114,12 @@ public:
void finalize() override;
void writeTo(uint8_t *Buf) override;
void addEntry(SymbolBody &Sym);
+ void addMipsEntry(SymbolBody &Sym, uintX_t Addend, RelExpr Expr);
bool addDynTlsEntry(SymbolBody &Sym);
bool addTlsIndex();
- bool empty() const { return MipsLocalEntries == 0 && Entries.empty(); }
- uintX_t getMipsLocalEntryOffset(uintX_t EntryValue);
+ bool empty() const { return MipsPageEntries == 0 && Entries.empty(); }
uintX_t getMipsLocalPageOffset(uintX_t Addr);
+ uintX_t getMipsGotOffset(const SymbolBody &B, uintX_t Addend) const;
uintX_t getGlobalDynAddr(const SymbolBody &B) const;
uintX_t getGlobalDynOffset(const SymbolBody &B) const;
uintX_t getNumEntries() const { return Entries.size(); }
@@ -142,10 +144,26 @@ public:
private:
std::vector<const SymbolBody *> Entries;
uint32_t TlsIndexOff = -1;
- uint32_t MipsLocalEntries = 0;
+ uint32_t MipsPageEntries = 0;
// Output sections referenced by MIPS GOT relocations.
llvm::SmallPtrSet<const OutputSectionBase<ELFT> *, 10> MipsOutSections;
llvm::DenseMap<uintX_t, size_t> MipsLocalGotPos;
+
+ // MIPS ABI requires to create unique GOT entry for each Symbol/Addend
+ // pairs. The `MipsGotMap` maps (S,A) pair to the GOT index in the `MipsLocal`
+ // or `MipsGlobal` vectors. In general it does not have a sence to take in
+ // account addend for preemptible symbols because the corresponding
+ // GOT entries should have one-to-one mapping with dynamic symbols table.
+ // But we use the same container's types for both kind of GOT entries
+ // to handle them uniformly.
+ typedef std::pair<const SymbolBody*, uintX_t> MipsGotEntry;
+ typedef std::vector<MipsGotEntry> MipsGotEntries;
+ llvm::DenseMap<MipsGotEntry, size_t> MipsGotMap;
+ MipsGotEntries MipsLocal;
+ MipsGotEntries MipsGlobal;
+
+ // Write MIPS-specific parts of the GOT.
+ void writeMipsGot(uint8_t *&Buf);
};
template <class ELFT>
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index f6e4b03ed3c..9b6105f9622 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -59,10 +59,10 @@ namespace lld {
namespace elf {
static bool refersToGotEntry(RelExpr Expr) {
- return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT_LOCAL ||
- Expr == R_MIPS_GOT_LOCAL_PAGE || Expr == R_GOT_PAGE_PC ||
- Expr == R_GOT_PC || Expr == R_GOT_FROM_END || Expr == R_TLSGD ||
- Expr == R_TLSGD_PC || Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE;
+ return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT_LOCAL_PAGE ||
+ Expr == R_MIPS_GOT_OFF || Expr == R_GOT_PAGE_PC || Expr == R_GOT_PC ||
+ Expr == R_GOT_FROM_END || Expr == R_TLSGD || Expr == R_TLSGD_PC ||
+ Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE;
}
static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
@@ -271,9 +271,9 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
const SymbolBody &Body) {
// These expressions always compute a constant
if (E == R_SIZE || E == R_GOT_FROM_END || E == R_GOT_OFF ||
- E == R_MIPS_GOT_LOCAL || E == R_MIPS_GOT_LOCAL_PAGE ||
- E == R_GOT_PAGE_PC || E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC ||
- E == R_TLSGD || E == R_PPC_PLT_OPD || E == R_TLSDESC_PAGE || E == R_HINT)
+ E == R_MIPS_GOT_LOCAL_PAGE || E == R_MIPS_GOT_OFF || E == R_GOT_PAGE_PC ||
+ E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC || E == R_TLSGD ||
+ E == R_PPC_PLT_OPD || E == R_TLSDESC_PAGE || E == R_HINT)
return true;
// These never do, except if the entire file is position dependent or if
@@ -466,8 +466,6 @@ static typename ELFT::uint computeAddend(const elf::ObjectFile<ELFT> &File,
// For details see p. 4-19 at
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
Addend += 4;
- if (Expr == R_GOT_OFF)
- Addend -= MipsGPOffset;
if (Expr == R_GOTREL) {
Addend -= MipsGPOffset;
if (Body.isLocal())
@@ -574,8 +572,8 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
// to the GOT entry and reads the GOT entry when it needs to perform
// a dynamic relocation.
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19
- if (Config->EMachine == EM_MIPS && !Body.isInGot())
- Out<ELFT>::Got->addEntry(Body);
+ if (Config->EMachine == EM_MIPS)
+ Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
continue;
}
@@ -605,18 +603,20 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
}
if (refersToGotEntry(Expr)) {
- if (Body.isInGot())
- continue;
- Out<ELFT>::Got->addEntry(Body);
-
- if (Config->EMachine == EM_MIPS)
+ if (Config->EMachine == EM_MIPS) {
// MIPS ABI has special rules to process GOT entries
// and doesn't require relocation entries for them.
// 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
+ Out<ELFT>::Got->addMipsEntry(Body, Addend, Expr);
+ continue;
+ }
+
+ if (Body.isInGot())
continue;
+ Out<ELFT>::Got->addEntry(Body);
if (Preemptible || (Config->Pic && !isAbsolute<ELFT>(Body))) {
uint32_t DynType;
if (Body.isTls())
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index 34612200999..56c14c1152e 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -28,8 +28,8 @@ enum RelExpr {
R_GOT_PAGE_PC,
R_GOT_PC,
R_HINT,
- R_MIPS_GOT_LOCAL,
R_MIPS_GOT_LOCAL_PAGE,
+ R_MIPS_GOT_OFF,
R_NEG_TLS,
R_PAGE_PC,
R_PC,
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 5cbf92fdf1a..0ba571b7e9a 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -92,12 +92,14 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther,
uint8_t Type)
- : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(true), Type(Type),
- StOther(StOther), NameOffset(NameOffset) {}
+ : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(true),
+ IsInGlobalMipsGot(false), Type(Type), StOther(StOther),
+ NameOffset(NameOffset) {}
SymbolBody::SymbolBody(Kind K, StringRef Name, uint8_t StOther, uint8_t Type)
- : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(false), Type(Type),
- StOther(StOther), Name({Name.data(), Name.size()}) {}
+ : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(false),
+ IsInGlobalMipsGot(false), Type(Type), StOther(StOther),
+ Name({Name.data(), Name.size()}) {}
// Returns true if a symbol can be replaced at load-time by a symbol
// with the same name defined in other ELF executable or DSO.
@@ -149,8 +151,7 @@ template <class ELFT> typename ELFT::uint SymbolBody::getGotVA() const {
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const {
- return (Out<ELFT>::Got->getMipsLocalEntriesNum() + GotIndex) *
- sizeof(typename ELFT::uint);
+ return GotIndex * sizeof(typename ELFT::uint);
}
template <class ELFT> typename ELFT::uint SymbolBody::getGotPltVA() const {
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 689ccef3e10..8b103ae889a 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -127,6 +127,9 @@ public:
// True if this is a local symbol.
unsigned IsLocal : 1;
+ // True if this symbol has an entry in the global part of MIPS GOT.
+ unsigned IsInGlobalMipsGot : 1;
+
// The following fields have the same meaning as the ELF symbol attributes.
uint8_t Type; // symbol type
uint8_t StOther; // st_other field value
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index a5fe030d762..3d16295c230 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -1745,9 +1745,7 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
// fallthrough
case R_MIPS_CALL16:
case R_MIPS_GOT_DISP:
- if (!S.isPreemptible())
- return R_MIPS_GOT_LOCAL;
- return R_GOT_OFF;
+ return R_MIPS_GOT_OFF;
case R_MIPS_GOT_PAGE:
return R_MIPS_GOT_LOCAL_PAGE;
}
diff --git a/lld/test/ELF/mips-64-disp.s b/lld/test/ELF/mips-64-disp.s
new file mode 100644
index 00000000000..1c66ba4fb9a
--- /dev/null
+++ b/lld/test/ELF/mips-64-disp.s
@@ -0,0 +1,89 @@
+# Check R_MIPS_GOT_DISP relocations against various kind of symbols.
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \
+# RUN: %p/Inputs/mips-pic.s -o %t.so.o
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.exe.o
+# RUN: ld.lld %t.so.o -shared -o %t.so
+# RUN: ld.lld %t.exe.o %t.so -o %t.exe
+# RUN: llvm-objdump -d -t %t.exe | FileCheck %s
+# RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck -check-prefix=GOT %s
+
+# REQUIRES: mips
+
+# CHECK: __start:
+# CHECK-NEXT: 20000: 24 42 80 40 addiu $2, $2, -32704
+# CHECK-NEXT: 20004: 24 42 80 20 addiu $2, $2, -32736
+# CHECK-NEXT: 20008: 24 42 80 28 addiu $2, $2, -32728
+# CHECK-NEXT: 2000c: 24 42 80 30 addiu $2, $2, -32720
+# CHECK-NEXT: 20010: 24 42 80 38 addiu $2, $2, -32712
+
+# CHECK: 0000000000020014 .text 00000000 foo
+# CHECK: 0000000000037ff0 .got 00000000 .hidden _gp
+# CHECK: 0000000000020000 .text 00000000 __start
+# CHECK: 0000000000000000 g F *UND* 00000000 foo1a
+
+# GOT: Relocations [
+# GOT-NEXT: ]
+# GOT-NEXT: Primary GOT {
+# GOT-NEXT: Canonical gp value: 0x37FF0
+# GOT-NEXT: Reserved entries [
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x30000
+# GOT-NEXT: Access: -32752
+# GOT-NEXT: Initial: 0x0
+# GOT-NEXT: Purpose: Lazy resolver
+# GOT-NEXT: }
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x30008
+# GOT-NEXT: Access: -32744
+# GOT-NEXT: Initial: 0x8000000000000000
+# GOT-NEXT: Purpose: Module pointer (GNU extension)
+# GOT-NEXT: }
+# GOT-NEXT: ]
+# GOT-NEXT: Local entries [
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x30010
+# GOT-NEXT: Access: -32736
+# GOT-NEXT: Initial: 0x20014
+# GOT-NEXT: }
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x30018
+# GOT-NEXT: Access: -32728
+# GOT-NEXT: Initial: 0x20004
+# GOT-NEXT: }
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x30020
+# GOT-NEXT: Access: -32720
+# GOT-NEXT: Initial: 0x20008
+# GOT-NEXT: }
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x30028
+# GOT-NEXT: Access: -32712
+# GOT-NEXT: Initial: 0x2000C
+# GOT-NEXT: }
+# GOT-NEXT: ]
+# GOT-NEXT: Global entries [
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x30030
+# GOT-NEXT: Access: -32704
+# GOT-NEXT: Initial: 0x0
+# GOT-NEXT: Value: 0x0
+# GOT-NEXT: Type: Function
+# GOT-NEXT: Section: Undefined
+# GOT-NEXT: Name: foo1a
+# GOT-NEXT: }
+# GOT-NEXT: ]
+# GOT-NEXT: Number of TLS and multi-GOT entries: 0
+# GOT-NEXT: }
+
+ .text
+ .global __start
+__start:
+ addiu $v0,$v0,%got_disp(foo1a) # R_MIPS_GOT_DISP
+ addiu $v0,$v0,%got_disp(foo) # R_MIPS_GOT_DISP
+ addiu $v0,$v0,%got_disp(.text+4) # R_MIPS_GOT_DISP
+ addiu $v0,$v0,%got_disp(.text+8) # R_MIPS_GOT_DISP
+ addiu $v0,$v0,%got_disp(.text+12) # R_MIPS_GOT_DISP
+
+foo:
+ nop
diff --git a/lld/test/ELF/mips-64-got.s b/lld/test/ELF/mips-64-got.s
index 7a078d6560b..52ce6fb4d35 100644
--- a/lld/test/ELF/mips-64-got.s
+++ b/lld/test/ELF/mips-64-got.s
@@ -13,14 +13,15 @@
# CHECK: __start:
# CHECK-NEXT: 20000: df 82 80 20 ld $2, -32736($gp)
-# CHECK-NEXT: 20004: 64 42 00 14 daddiu $2, $2, 20
-# CHECK-NEXT: 20008: 24 42 80 30 addiu $2, $2, -32720
+# CHECK-NEXT: 20004: 64 42 00 18 daddiu $2, $2, 24
+# CHECK-NEXT: 20008: 24 42 80 38 addiu $2, $2, -32712
# CHECK-NEXT: 2000c: 24 42 80 28 addiu $2, $2, -32728
+# CHECK-NEXT: 20010: 24 42 80 30 addiu $2, $2, -32720
-# CHECK: 0000000000020014 .text 00000000 foo
+# CHECK: 0000000000020018 .text 00000000 foo
# CHECK: 0000000000037ff0 .got 00000000 .hidden _gp
# CHECK: 0000000000020000 .text 00000000 __start
-# CHECK: 0000000000020010 .text 00000000 bar
+# CHECK: 0000000000020014 .text 00000000 bar
# GOT: Relocations [
# GOT-NEXT: ]
@@ -49,13 +50,18 @@
# GOT-NEXT: Entry {
# GOT-NEXT: Address: 0x30018
# GOT-NEXT: Access: -32728
-# GOT-NEXT: Initial: 0x20010
+# GOT-NEXT: Initial: 0x20014
# GOT-NEXT: }
-# GOT-NEXT: ]
-# GOT-NEXT: Global entries [
# GOT-NEXT: Entry {
# GOT-NEXT: Address: 0x30020
# GOT-NEXT: Access: -32720
+# GOT-NEXT: Initial: 0x20018
+# GOT-NEXT: }
+# GOT-NEXT: ]
+# GOT-NEXT: Global entries [
+# GOT-NEXT: Entry {
+# GOT-NEXT: Address: 0x30028
+# GOT-NEXT: Access: -32712
# GOT-NEXT: Initial: 0x0
# GOT-NEXT: Value: 0x0
# GOT-NEXT: Type: Function
@@ -73,6 +79,7 @@ __start:
daddiu $v0,$v0,%got_ofst(foo) # R_MIPS_GOT_OFST
addiu $v0,$v0,%got_disp(foo1a) # R_MIPS_GOT_DISP
addiu $v0,$v0,%got_disp(bar) # R_MIPS_GOT_DISP
+ addiu $v0,$v0,%got_disp(foo) # R_MIPS_GOT_DISP
bar:
nop
diff --git a/lld/test/ELF/mips-dynamic.s b/lld/test/ELF/mips-dynamic.s
index cceaf6d0cbd..797628b7b51 100644
--- a/lld/test/ELF/mips-dynamic.s
+++ b/lld/test/ELF/mips-dynamic.s
@@ -71,8 +71,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-got16.s b/lld/test/ELF/mips-got16.s
index 22f4b07ceca..ef80418ef03 100644
--- a/lld/test/ELF/mips-got16.s
+++ b/lld/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)
#
@@ -67,14 +67,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: Access: -327
+# GOT-NEXT: Initial: 0x51008
+# ^-- 'bar' address
# GOT-NEXT: }
# GOT-NEXT: ]
# GOT-NEXT: Global entries [
diff --git a/lld/test/ELF/mips-plt-copy.s b/lld/test/ELF/mips-plt-copy.s
index 58883d88456..bdbb1d71f31 100644
--- a/lld/test/ELF/mips-plt-copy.s
+++ b/lld/test/ELF/mips-plt-copy.s
@@ -12,8 +12,8 @@
# 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-NEXT: 0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0
# CHECK-NEXT: }
# CHECK-NEXT: Section ({{.*}}) .rel.plt {
# CHECK-NEXT: 0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo0 0x0
diff --git a/lld/test/ELF/mips-sto-plt.s b/lld/test/ELF/mips-sto-plt.s
index bd8de416680..18964e96d05 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: 0x20050
# 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: }
OpenPOWER on IntegriCloud