summaryrefslogtreecommitdiffstats
path: root/lld/lib
diff options
context:
space:
mode:
authorSimon Atanasyan <simon@atanasyan.com>2014-06-07 13:20:53 +0000
committerSimon Atanasyan <simon@atanasyan.com>2014-06-07 13:20:53 +0000
commitc8e86fb0323a9cba7e1745e68c713ff0dee3f85c (patch)
tree77fb8c25a4fef5cf4df16c3a4c7abcf9a74619c1 /lld/lib
parent4ba22f08133c0a5dbccaa6a442219693c1d677f0 (diff)
downloadbcm5719-llvm-c8e86fb0323a9cba7e1745e68c713ff0dee3f85c.tar.gz
bcm5719-llvm-c8e86fb0323a9cba7e1745e68c713ff0dee3f85c.zip
[Mips] Handle Mips TLS relocations R_MIPS_TLS_GOTTPREL / R_MIPS_TLS_GD / R_MIPS_TLS_LDM etc.
llvm-svn: 210394
Diffstat (limited to 'lld/lib')
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h13
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h8
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp3
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp16
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp106
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h41
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp8
7 files changed, 168 insertions, 27 deletions
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h b/lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h
index afdfc11ebe4..9d1c5888f8f 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsELFFile.h
@@ -118,6 +118,7 @@ public:
/// \brief .tdata section address plus fixed offset.
uint64_t getTPOffset() const { return *_tpOff; }
+ uint64_t getDTPOffset() const { return *_dtpOff; }
private:
typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
@@ -125,10 +126,11 @@ private:
typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel_Iter Elf_Rel_Iter;
- enum { TP_OFFSET = 0x7000 };
+ enum { TP_OFFSET = 0x7000, DTP_OFFSET = 0x8000 };
llvm::Optional<int64_t> _gp0;
llvm::Optional<uint64_t> _tpOff;
+ llvm::Optional<uint64_t> _dtpOff;
ErrorOr<ELFDefinedAtom<ELFT> *> handleDefinedSymbol(
StringRef symName, StringRef sectionName, const Elf_Sym *sym,
@@ -155,8 +157,10 @@ private:
assert(raw.size() == sizeof(Elf_RegInfo) &&
"Invalid size of RegInfo section");
_gp0 = reinterpret_cast<const Elf_RegInfo *>(raw.data())->ri_gp_value;
- } else if (!_tpOff.hasValue() && section.sh_flags & llvm::ELF::SHF_TLS)
+ } else if (!_tpOff.hasValue() && section.sh_flags & llvm::ELF::SHF_TLS) {
_tpOff = section.sh_addr + TP_OFFSET;
+ _dtpOff = section.sh_addr + DTP_OFFSET;
+ }
}
return error_code();
}
@@ -201,6 +205,11 @@ private:
case llvm::ELF::R_MIPS_HI16:
case llvm::ELF::R_MIPS_LO16:
case llvm::ELF::R_MIPS_GOT16:
+ case llvm::ELF::R_MIPS_TLS_GD:
+ case llvm::ELF::R_MIPS_TLS_LDM:
+ case llvm::ELF::R_MIPS_TLS_GOTTPREL:
+ case llvm::ELF::R_MIPS_TLS_DTPREL_HI16:
+ case llvm::ELF::R_MIPS_TLS_DTPREL_LO16:
case llvm::ELF::R_MIPS_TLS_TPREL_HI16:
case llvm::ELF::R_MIPS_TLS_TPREL_LO16:
return *(int16_t *)ap;
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h b/lld/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h
index 65034d279e5..8f28312a1d9 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsExecutableWriter.h
@@ -59,6 +59,14 @@ template <class ELFT>
void MipsExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
// MIPS ABI requires to add to dynsym even undefined symbols
// if they have a corresponding entries in a global part of GOT.
+ for (auto sec : this->_layout.sections())
+ if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
+ for (const auto &atom : section->atoms()) {
+ if (_writeHelper.hasGlobalGOTEntry(atom->_atom))
+ this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
+ atom->_virtualAddr, atom);
+ }
+
for (const UndefinedAtom *a : file.undefined())
// FIXME (simon): Consider to move this check to the
// MipsELFUndefinedAtom class method. That allows to
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
index 9e0e81d3534..946c96c7fa2 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
@@ -56,6 +56,9 @@ bool MipsLinkingContext::isDynamicRelocation(const DefinedAtom &,
switch (r.kindValue()) {
case llvm::ELF::R_MIPS_COPY:
case llvm::ELF::R_MIPS_REL32:
+ case llvm::ELF::R_MIPS_TLS_DTPMOD32:
+ case llvm::ELF::R_MIPS_TLS_DTPREL32:
+ case llvm::ELF::R_MIPS_TLS_TPREL32:
return true;
default:
return false;
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
index a1e0ea36237..d3665022fbc 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
@@ -92,14 +92,14 @@ static void relocGOT(uint8_t *location, uint64_t P, uint64_t S, int64_t A,
applyReloc(location, G, 0xffff);
}
-/// \brief R_MIPS_TLS_TPREL_HI16, LLD_R_MIPS_HI16
+/// \brief R_MIPS_TLS_DTPREL_HI16, R_MIPS_TLS_TPREL_HI16, LLD_R_MIPS_HI16
/// (S + A) >> 16
static void relocGeneralHi16(uint8_t *location, uint64_t S, int64_t A) {
int32_t result = S + A + 0x8000;
applyReloc(location, result >> 16, 0xffff);
}
-/// \brief R_MIPS_TLS_TPREL_LO16, LLD_R_MIPS_LO16
+/// \brief R_MIPS_TLS_DTPREL_LO16, R_MIPS_TLS_TPREL_LO16, LLD_R_MIPS_LO16
/// S + A
static void relocGeneralLo16(uint8_t *location, uint64_t S, int64_t A) {
int32_t result = S + A;
@@ -158,9 +158,18 @@ error_code MipsTargetRelocationHandler::applyRelocation(
case R_MIPS_CALL16:
relocGOT(location, relocVAddress, targetVAddress, ref.addend(), gpAddr);
break;
+ case R_MIPS_TLS_GD:
+ relocGOT(location, relocVAddress, targetVAddress, ref.addend(), gpAddr);
+ break;
+ case R_MIPS_TLS_LDM:
+ case R_MIPS_TLS_GOTTPREL:
+ relocGOT(location, relocVAddress, targetVAddress, ref.addend(), gpAddr);
+ break;
+ case R_MIPS_TLS_DTPREL_HI16:
case R_MIPS_TLS_TPREL_HI16:
relocGeneralHi16(location, targetVAddress, ref.addend());
break;
+ case R_MIPS_TLS_DTPREL_LO16:
case R_MIPS_TLS_TPREL_LO16:
relocGeneralLo16(location, targetVAddress, ref.addend());
break;
@@ -173,6 +182,9 @@ error_code MipsTargetRelocationHandler::applyRelocation(
case R_MIPS_REL32:
case R_MIPS_JUMP_SLOT:
case R_MIPS_COPY:
+ case R_MIPS_TLS_DTPMOD32:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_TPREL32:
// Ignore runtime relocations.
break;
case R_MIPS_PC32:
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
index 16f8af839f1..5e507255cac 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
@@ -28,6 +28,12 @@ static const uint8_t mipsGotModulePointerAtomContent[] = {
0x00, 0x00, 0x00, 0x80
};
+// TLS GD Entry
+static const uint8_t mipsGotTlsGdAtomContent[] = {
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
// PLT0 entry
static const uint8_t mipsPlt0AtomContent[] = {
0x00, 0x00, 0x1c, 0x3c, // lui $28, %hi(&GOTPLT[0])
@@ -86,6 +92,16 @@ public:
}
};
+/// \brief MIPS GOT TLS GD entry.
+class GOTTLSGdAtom : public MipsGOTAtom {
+public:
+ GOTTLSGdAtom(const File &f) : MipsGOTAtom(f) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(mipsGotTlsGdAtomContent);
+ }
+};
+
class PLT0Atom : public PLTAtom {
public:
PLT0Atom(const File &f) : PLTAtom(f, ".plt") {}
@@ -156,12 +172,24 @@ private:
/// \brief Map Atoms to global GOT entries.
llvm::DenseMap<const Atom *, GOTAtom *> _gotGlobalMap;
+ /// \brief Map Atoms to TLS GOT entries.
+ llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSMap;
+
+ /// \brief Map Atoms to TLS GD GOT entries.
+ llvm::DenseMap<const Atom *, GOTAtom *> _gotTLSGdMap;
+
+ /// \brief GOT entry for the R_MIPS_TLS_LDM relocation.
+ GOTTLSGdAtom *_gotLDMEntry;
+
/// \brief the list of local GOT atoms.
std::vector<GOTAtom *> _localGotVector;
/// \brief the list of global GOT atoms.
std::vector<GOTAtom *> _globalGotVector;
+ /// \brief the list of TLS GOT atoms.
+ std::vector<GOTAtom *> _tlsGotVector;
+
/// \brief Map Atoms to their PLT entries.
llvm::DenseMap<const Atom *, PLTAtom *> _pltMap;
@@ -205,10 +233,12 @@ private:
void handle26(Reference &ref);
void handleGOT(Reference &ref);
void handleGPRel(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
- void handleTLS(const MipsELFDefinedAtom<ELFT> &atom, Reference &ref);
const GOTAtom *getLocalGOTEntry(const Reference &ref);
const GOTAtom *getGlobalGOTEntry(const Atom *a);
+ const GOTAtom *getTLSGOTEntry(const Atom *a);
+ const GOTAtom *getTLSGdGOTEntry(const Atom *a);
+ const GOTAtom *getTLSLdmGOTEntry(const Atom *a);
PLTAtom *getPLTEntry(const Atom *a);
const LA25Atom *getLA25Entry(const Atom *a);
const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a);
@@ -230,7 +260,7 @@ private:
template <typename ELFT>
RelocationPass<ELFT>::RelocationPass(MipsLinkingContext &context)
- : _context(context), _file(context) {
+ : _context(context), _file(context), _gotLDMEntry(nullptr) {
_localGotVector.push_back(new (_file._alloc) GOT0Atom(_file));
_localGotVector.push_back(new (_file._alloc) GOTModulePointerAtom(_file));
}
@@ -275,6 +305,11 @@ void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) {
mf->addAtom(*got);
}
+ for (auto &got : _tlsGotVector) {
+ got->setOrdinal(ordinal++);
+ mf->addAtom(*got);
+ }
+
for (auto &plt : _pltVector) {
DEBUG_WITH_TYPE("MipsGOT", llvm::dbgs() << "[ PLT ] Adding " << plt->name()
<< "\n");
@@ -326,9 +361,22 @@ void RelocationPass<ELFT>::handleReference(const MipsELFDefinedAtom<ELFT> &atom,
case R_MIPS_GPREL32:
handleGPRel(atom, ref);
break;
+ case R_MIPS_TLS_DTPREL_HI16:
+ case R_MIPS_TLS_DTPREL_LO16:
+ ref.setAddend(ref.addend() - atom.file().getDTPOffset());
+ break;
case R_MIPS_TLS_TPREL_HI16:
case R_MIPS_TLS_TPREL_LO16:
- handleTLS(atom, ref);
+ ref.setAddend(ref.addend() - atom.file().getTPOffset());
+ break;
+ case R_MIPS_TLS_GD:
+ ref.setTarget(getTLSGdGOTEntry(ref.target()));
+ break;
+ case R_MIPS_TLS_LDM:
+ ref.setTarget(getTLSLdmGOTEntry(ref.target()));
+ break;
+ case R_MIPS_TLS_GOTTPREL:
+ ref.setTarget(getTLSGOTEntry(ref.target()));
break;
}
}
@@ -513,15 +561,6 @@ void RelocationPass<ELFT>::handleGPRel(const MipsELFDefinedAtom<ELFT> &atom,
}
template <typename ELFT>
-void RelocationPass<ELFT>::handleTLS(const MipsELFDefinedAtom<ELFT> &atom,
- Reference &ref) {
- assert((ref.kindValue() == R_MIPS_TLS_TPREL_HI16 ||
- ref.kindValue() == R_MIPS_TLS_TPREL_LO16) &&
- "Unexpected kind of relocation");
- ref.setAddend(ref.addend() - atom.file().getTPOffset());
-}
-
-template <typename ELFT>
bool RelocationPass<ELFT>::isLocalCall(const Atom *a) const {
Atom::Scope scope;
if (auto *da = dyn_cast<DefinedAtom>(a))
@@ -601,6 +640,49 @@ const GOTAtom *RelocationPass<ELFT>::getGlobalGOTEntry(const Atom *a) {
return ga;
}
+template <typename ELFT>
+const GOTAtom *RelocationPass<ELFT>::getTLSGOTEntry(const Atom *a) {
+ auto got = _gotTLSMap.find(a);
+ if (got != _gotTLSMap.end())
+ return got->second;
+
+ auto ga = new (_file._alloc) GOT0Atom(_file);
+ _gotTLSMap[a] = ga;
+
+ _tlsGotVector.push_back(ga);
+ ga->addReferenceELF_Mips(R_MIPS_TLS_TPREL32, 0, a, 0);
+
+ return ga;
+}
+
+template <typename ELFT>
+const GOTAtom *RelocationPass<ELFT>::getTLSGdGOTEntry(const Atom *a) {
+ auto got = _gotTLSGdMap.find(a);
+ if (got != _gotTLSGdMap.end())
+ return got->second;
+
+ auto ga = new (_file._alloc) GOTTLSGdAtom(_file);
+ _gotTLSGdMap[a] = ga;
+
+ _tlsGotVector.push_back(ga);
+ ga->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, a, 0);
+ ga->addReferenceELF_Mips(R_MIPS_TLS_DTPREL32, 4, a, 0);
+
+ return ga;
+}
+
+template <typename ELFT>
+const GOTAtom *RelocationPass<ELFT>::getTLSLdmGOTEntry(const Atom *a) {
+ if (_gotLDMEntry)
+ return _gotLDMEntry;
+
+ _gotLDMEntry = new (_file._alloc) GOTTLSGdAtom(_file);
+ _tlsGotVector.push_back(_gotLDMEntry);
+ _gotLDMEntry->addReferenceELF_Mips(R_MIPS_TLS_DTPMOD32, 0, _gotLDMEntry, 0);
+
+ return _gotLDMEntry;
+}
+
template <typename ELFT> void RelocationPass<ELFT>::createPLTHeader() {
assert(_pltVector.empty() && _gotpltVector.empty());
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h b/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
index a8ae8b3d11d..05c32b781c5 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
@@ -21,21 +21,22 @@ public:
MipsGOTSection(const MipsLinkingContext &context)
: AtomSection<ELFType>(context, ".got", DefinedAtom::typeGOT,
DefinedAtom::permRW_,
- MipsTargetLayout<ELFType>::ORDER_GOT) {
+ MipsTargetLayout<ELFType>::ORDER_GOT),
+ _hasNonLocal(false), _localCount(0) {
this->_flags |= SHF_MIPS_GPREL;
this->_align2 = 4;
}
/// \brief Number of local GOT entries.
- std::size_t getLocalCount() const {
- return this->_atoms.size() - getGlobalCount();
- }
+ std::size_t getLocalCount() const { return _localCount; }
/// \brief Number of global GOT entries.
std::size_t getGlobalCount() const { return _posMap.size(); }
/// \brief Does the atom have a global GOT entry?
- bool hasGlobalGOTEntry(const Atom *a) const { return _posMap.count(a); }
+ bool hasGlobalGOTEntry(const Atom *a) const {
+ return _posMap.count(a) || _tlsMap.count(a);
+ }
/// \brief Compare two atoms accordingly theirs positions in the GOT.
bool compare(const Atom *a, const Atom *b) const {
@@ -51,24 +52,42 @@ public:
const lld::AtomLayout &appendAtom(const Atom *atom) override {
const DefinedAtom *da = dyn_cast<DefinedAtom>(atom);
- const Atom *ta = nullptr;
for (const auto &r : *da) {
if (r->kindNamespace() != lld::Reference::KindNamespace::ELF)
continue;
assert(r->kindArch() == Reference::KindArch::Mips);
- if (r->kindValue() == LLD_R_MIPS_GLOBAL_GOT) {
- ta = r->target();
- break;
+ switch (r->kindValue()) {
+ case LLD_R_MIPS_GLOBAL_GOT:
+ _hasNonLocal = true;
+ _posMap[r->target()] = _posMap.size();
+ return AtomSection<ELFType>::appendAtom(atom);
+ case R_MIPS_TLS_TPREL32:
+ case R_MIPS_TLS_DTPREL32:
+ _hasNonLocal = true;
+ _tlsMap[r->target()] = _tlsMap.size();
+ return AtomSection<ELFType>::appendAtom(atom);
+ case R_MIPS_TLS_DTPMOD32:
+ _hasNonLocal = true;
+ return AtomSection<ELFType>::appendAtom(atom);
}
}
- if (ta)
- _posMap[ta] = _posMap.size();
+ if (!_hasNonLocal)
+ ++_localCount;
return AtomSection<ELFType>::appendAtom(atom);
}
private:
+ /// \brief True if the GOT contains non-local entries.
+ bool _hasNonLocal;
+
+ /// \brief Number of local GOT entries.
+ std::size_t _localCount;
+
+ /// \brief Map TLS Atoms to their GOT entry index.
+ llvm::DenseMap<const Atom *, std::size_t> _tlsMap;
+
/// \brief Map Atoms to their GOT entry index.
llvm::DenseMap<const Atom *, std::size_t> _posMap;
};
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
index 1c90031a47b..fc32ba3d398 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
@@ -57,6 +57,14 @@ const Registry::KindStrings MipsTargetHandler::kindStrings[] = {
LLD_KIND_STRING_ENTRY(R_MIPS_CALL16),
LLD_KIND_STRING_ENTRY(R_MIPS_GPREL32),
LLD_KIND_STRING_ENTRY(R_MIPS_JALR),
+ LLD_KIND_STRING_ENTRY(R_MIPS_TLS_DTPMOD32),
+ LLD_KIND_STRING_ENTRY(R_MIPS_TLS_DTPREL32),
+ LLD_KIND_STRING_ENTRY(R_MIPS_TLS_GD),
+ LLD_KIND_STRING_ENTRY(R_MIPS_TLS_LDM),
+ LLD_KIND_STRING_ENTRY(R_MIPS_TLS_GOTTPREL),
+ LLD_KIND_STRING_ENTRY(R_MIPS_TLS_TPREL32),
+ LLD_KIND_STRING_ENTRY(R_MIPS_TLS_DTPREL_HI16),
+ LLD_KIND_STRING_ENTRY(R_MIPS_TLS_DTPREL_LO16),
LLD_KIND_STRING_ENTRY(R_MIPS_TLS_TPREL_HI16),
LLD_KIND_STRING_ENTRY(R_MIPS_TLS_TPREL_LO16),
LLD_KIND_STRING_ENTRY(R_MIPS_COPY),
OpenPOWER on IntegriCloud