summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/ELF/Mips
diff options
context:
space:
mode:
authorSimon Atanasyan <simon@atanasyan.com>2014-01-17 21:18:37 +0000
committerSimon Atanasyan <simon@atanasyan.com>2014-01-17 21:18:37 +0000
commit362bdc125e94b32b852b134dba9d67ad3075c6fd (patch)
tree91c3ac42f475b6f9877dd140ad24e7c604d33422 /lld/lib/ReaderWriter/ELF/Mips
parent66338224be6072b9af6f87aee0e3078076bfb4e3 (diff)
downloadbcm5719-llvm-362bdc125e94b32b852b134dba9d67ad3075c6fd.tar.gz
bcm5719-llvm-362bdc125e94b32b852b134dba9d67ad3075c6fd.zip
[Mips] Implement .plt and .got.plt section creation.
llvm-svn: 199516
Diffstat (limited to 'lld/lib/ReaderWriter/ELF/Mips')
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp13
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h7
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp21
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp139
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp3
-rw-r--r--lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h2
6 files changed, 182 insertions, 3 deletions
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
index c83b891b58c..280943720f8 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.cpp
@@ -56,3 +56,16 @@ void MipsLinkingContext::addPasses(PassManager &pm) {
pm.add(std::move(pass));
ELFLinkingContext::addPasses(pm);
}
+
+bool MipsLinkingContext::isPLTRelocation(const DefinedAtom &,
+ const Reference &r) const {
+ if (r.kindNamespace() != Reference::KindNamespace::ELF)
+ return false;
+ assert(r.kindArch() == Reference::KindArch::Mips);
+ switch (r.kindValue()) {
+ case llvm::ELF::R_MIPS_JUMP_SLOT:
+ return true;
+ default:
+ return false;
+ }
+}
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h
index 25c8fd99795..797964dd372 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsLinkingContext.h
@@ -21,7 +21,11 @@ enum {
/// \brief The same as R_MIPS_GOT16 but for global symbols.
LLD_R_MIPS_GLOBAL_GOT16 = 1025,
/// \brief The same as R_MIPS_26 but for global symbols.
- LLD_R_MIPS_GLOBAL_26 = 1026
+ LLD_R_MIPS_GLOBAL_26 = 1026,
+ /// \brief Setup hi 16 bits using the symbol this reference refers to.
+ LLD_R_MIPS_HI16 = 1027,
+ /// \brief Setup low 16 bits using the symbol this reference refers to.
+ LLD_R_MIPS_LO16 = 1028
};
typedef llvm::object::ELFType<llvm::support::little, 2, false> Mips32ElELFType;
@@ -41,6 +45,7 @@ public:
virtual StringRef entrySymbolName() const;
virtual StringRef getDefaultInterpreter() const;
virtual void addPasses(PassManager &pm);
+ virtual bool isPLTRelocation(const DefinedAtom &, const Reference &r) const;
};
} // elf
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
index 6e14bf3196e..e51ab60bc24 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationHandler.cpp
@@ -105,6 +105,18 @@ void relocCall16(uint8_t *location, uint64_t P, uint64_t S, int64_t A,
applyReloc(location, result);
}
+/// \brief LLD_R_MIPS_HI16
+void relocLldHi16(uint8_t *location, uint64_t S) {
+ int32_t result = lld::scatterBits<uint32_t>((S + 0x8000) >> 16, 0xffff);
+ applyReloc(location, result);
+}
+
+/// \brief LLD_R_MIPS_LO16
+void relocLldLo16(uint8_t *location, uint64_t S) {
+ int32_t result = lld::scatterBits<uint32_t>(S, 0xffff);
+ applyReloc(location, result);
+}
+
} // end anon namespace
MipsTargetRelocationHandler::MipsTargetRelocationHandler(
@@ -200,6 +212,9 @@ error_code MipsTargetRelocationHandler::applyRelocation(
case R_MIPS_JALR:
// We do not do JALR optimization now.
break;
+ case R_MIPS_JUMP_SLOT:
+ // Ignore runtime relocations.
+ break;
case LLD_R_MIPS_GLOBAL_GOT:
// Do nothing.
break;
@@ -210,6 +225,12 @@ error_code MipsTargetRelocationHandler::applyRelocation(
case LLD_R_MIPS_GLOBAL_26:
reloc26(location, relocVAddress, targetVAddress, false);
break;
+ case LLD_R_MIPS_HI16:
+ relocLldHi16(location, targetVAddress);
+ break;
+ case LLD_R_MIPS_LO16:
+ relocLldLo16(location, targetVAddress);
+ break;
default: {
std::string str;
llvm::raw_string_ostream s(str);
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
index 09d1d9d008e..7adef094184 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
@@ -24,6 +24,26 @@ const uint8_t mipsGot0AtomContent[] = { 0x00, 0x00, 0x00, 0x00 };
// Module pointer
const uint8_t mipsGotModulePointerAtomContent[] = { 0x00, 0x00, 0x00, 0x80 };
+// PLT0 entry
+const uint8_t mipsPlt0AtomContent[] = {
+ 0x00, 0x00, 0x1c, 0x3c, // lui $28, %hi(&GOTPLT[0])
+ 0x00, 0x00, 0x99, 0x8f, // lw $25, %lo(&GOTPLT[0])($28)
+ 0x00, 0x00, 0x9c, 0x27, // addiu $28, $28, %lo(&GOTPLT[0])
+ 0x23, 0xc0, 0x1c, 0x03, // subu $24, $24, $28
+ 0x21, 0x78, 0xe0, 0x03, // move $15, $31
+ 0x82, 0xc0, 0x18, 0x00, // srl $24, $24, 2
+ 0x09, 0xf8, 0x20, 0x03, // jalr $25
+ 0xfe, 0xff, 0x18, 0x27 // subu $24, $24, 2
+};
+
+// Regular PLT entry
+const uint8_t mipsPltAAtomContent[] = {
+ 0x00, 0x00, 0x0f, 0x3c, // lui $15, %hi(.got.plt entry)
+ 0x00, 0x00, 0xf9, 0x8d, // l[wd] $25, %lo(.got.plt entry)($15)
+ 0x08, 0x00, 0x20, 0x03, // jr $25
+ 0x00, 0x00, 0xf8, 0x25 // addiu $24, $15, %lo(.got.plt entry)
+};
+
/// \brief Abstract base class represent MIPS GOT entries.
class MipsGOTAtom : public GOTAtom {
public:
@@ -52,6 +72,36 @@ public:
}
};
+class PLT0Atom : public PLTAtom {
+public:
+ PLT0Atom(const File &f) : PLTAtom(f, ".plt") {}
+
+ virtual ArrayRef<uint8_t> rawContent() const {
+ return llvm::makeArrayRef(mipsPlt0AtomContent);
+ }
+};
+
+class PLTAAtom : public PLTAtom {
+public:
+ PLTAAtom(const File &f) : PLTAtom(f, ".plt") {}
+
+ virtual ArrayRef<uint8_t> rawContent() const {
+ return llvm::makeArrayRef(mipsPltAAtomContent);
+ }
+};
+
+/// \brief MIPS GOT PLT entry
+class GOTPLTAtom : public GOTAtom {
+public:
+ GOTPLTAtom(const File &f) : GOTAtom(f, ".got.plt") {}
+
+ virtual Alignment alignment() const { return Alignment(2); }
+
+ virtual ArrayRef<uint8_t> rawContent() const {
+ return llvm::makeArrayRef(mipsGot0AtomContent);
+ }
+};
+
class RelocationPassFile : public SimpleFile {
public:
RelocationPassFile(const ELFLinkingContext &ctx)
@@ -90,6 +140,20 @@ public:
got->setOrdinal(ordinal++);
mf->addAtom(*got);
}
+
+ for (auto &plt : _pltVector) {
+ DEBUG_WITH_TYPE("MipsGOT", llvm::dbgs() << "[ PLT ] Adding "
+ << plt->name() << "\n");
+ plt->setOrdinal(ordinal++);
+ mf->addAtom(*plt);
+ }
+
+ for (auto &gotplt : _gotpltVector) {
+ DEBUG_WITH_TYPE("MipsGOT", llvm::dbgs() << "[ GOTPLT ] Adding "
+ << gotplt->name() << "\n");
+ gotplt->setOrdinal(ordinal++);
+ mf->addAtom(*gotplt);
+ }
}
private:
@@ -105,6 +169,15 @@ private:
/// \brief the list of global GOT atoms.
std::vector<GOTAtom *> _globalGotVector;
+ /// \brief Map Atoms to their PLT entries.
+ llvm::DenseMap<const Atom *, PLTAtom *> _pltMap;
+
+ /// \brief the list of PLT atoms.
+ std::vector<PLTAtom *> _pltVector;
+
+ /// \brief the list of GOTPLT atoms.
+ std::vector<GOTAtom *> _gotpltVector;
+
/// \brief Handle a specific reference.
void handleReference(const DefinedAtom &atom, const Reference &ref) {
if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
@@ -131,7 +204,8 @@ private:
if (ref.kindValue() == R_MIPS_26 && !isLocal(ref.target()))
const_cast<Reference &>(ref).setKindValue(LLD_R_MIPS_GLOBAL_26);
- // FIXME (simon): Create PLT entry.
+ if (isa<SharedLibraryAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getPLTEntry(ref.target()));
}
void handleGOT(const Reference &ref) {
@@ -187,6 +261,69 @@ private:
return ga;
}
+
+ void createPLTHeader() {
+ assert(_pltVector.empty() && _gotpltVector.empty());
+
+ auto pa = new (_file._alloc) PLT0Atom(_file);
+ _pltVector.push_back(pa);
+
+ auto ga0 = new (_file._alloc) GOTPLTAtom(_file);
+ _gotpltVector.push_back(ga0);
+ auto ga1 = new (_file._alloc) GOTPLTAtom(_file);
+ _gotpltVector.push_back(ga1);
+
+ // Setup reference to fixup the PLT0 entry.
+ pa->addReferenceELF_Mips(LLD_R_MIPS_HI16, 0, ga0, 0);
+ pa->addReferenceELF_Mips(LLD_R_MIPS_LO16, 4, ga0, 0);
+ pa->addReferenceELF_Mips(LLD_R_MIPS_LO16, 8, ga0, 0);
+
+ DEBUG_WITH_TYPE("MipsGOT", {
+ pa->_name = "__plt0";
+ llvm::dbgs() << "[ PLT ] Create PLT0\n";
+ ga0->_name = "__gotplt0";
+ llvm::dbgs() << "[ GOTPLT ] Create GOTPLT0\n";
+ ga1->_name = "__gotplt1";
+ llvm::dbgs() << "[ GOTPLT ] Create GOTPLT1\n";
+ });
+ }
+
+ const PLTAtom *getPLTEntry(const Atom *a) {
+ auto plt = _pltMap.find(a);
+ if (plt != _pltMap.end())
+ return plt->second;
+
+ if (_pltVector.empty())
+ createPLTHeader();
+
+ auto pa = new (_file._alloc) PLTAAtom(_file);
+ _pltMap[a] = pa;
+ _pltVector.push_back(pa);
+
+ auto ga = new (_file._alloc) GOTPLTAtom(_file);
+ _gotpltVector.push_back(ga);
+
+ // Setup reference to fixup the PLT entry.
+ pa->addReferenceELF_Mips(LLD_R_MIPS_HI16, 0, ga, 0);
+ pa->addReferenceELF_Mips(LLD_R_MIPS_LO16, 4, ga, 0);
+ pa->addReferenceELF_Mips(LLD_R_MIPS_LO16, 12, ga, 0);
+
+ // Setup reference to assign initial value to the .got.plt entry.
+ ga->addReferenceELF_Mips(R_MIPS_32, 0, _pltVector.front(), 0);
+ // Create dynamic relocation to adjust the .got.plt entry at runtime.
+ ga->addReferenceELF_Mips(R_MIPS_JUMP_SLOT, 0, a, 0);
+
+ DEBUG_WITH_TYPE("MipsGOT", {
+ pa->_name = "__plt_";
+ pa->_name += a->name();
+ llvm::dbgs() << "[ PLT ] Create " << a->name() << "\n";
+ ga->_name = "__got_plt_";
+ ga->_name += a->name();
+ llvm::dbgs() << "[ GOTPLT ] Create " << a->name() << "\n";
+ });
+
+ return pa;
+ }
};
} // end anon namespace
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
index 704e994a15a..5b3ea762b7f 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.cpp
@@ -201,8 +201,11 @@ const Registry::KindStrings MipsTargetHandler::kindStrings[] = {
LLD_KIND_STRING_ENTRY(R_MIPS_GOT16),
LLD_KIND_STRING_ENTRY(R_MIPS_CALL16),
LLD_KIND_STRING_ENTRY(R_MIPS_JALR),
+ LLD_KIND_STRING_ENTRY(R_MIPS_JUMP_SLOT),
LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_GOT),
LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_GOT16),
LLD_KIND_STRING_ENTRY(LLD_R_MIPS_GLOBAL_26),
+ LLD_KIND_STRING_ENTRY(LLD_R_MIPS_HI16),
+ LLD_KIND_STRING_ENTRY(LLD_R_MIPS_LO16),
LLD_KIND_STRING_END
};
diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
index f826d702c12..d6e83372254 100644
--- a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
+++ b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h
@@ -35,7 +35,7 @@ public:
createSection(StringRef name, int32_t type,
DefinedAtom::ContentPermissions permissions,
Layout::SectionOrder order) {
- if (type == DefinedAtom::typeGOT)
+ if (type == DefinedAtom::typeGOT && name == ".got")
return _gotSection;
return DefaultLayout<ELFType>::createSection(name, type, permissions,
order);
OpenPOWER on IntegriCloud