summaryrefslogtreecommitdiff
path: root/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp')
-rw-r--r--lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp241
1 files changed, 163 insertions, 78 deletions
diff --git a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp
index 0bd12958b27b..4d94a793665c 100644
--- a/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp
+++ b/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp
@@ -28,52 +28,79 @@ using namespace lld;
using namespace lld::elf;
using namespace llvm::ELF;
-namespace {
// .got values
-const uint8_t AArch64GotAtomContent[8] = {0};
+static const uint8_t AArch64GotAtomContent[8] = {0};
+
+// tls descriptor .got values, the layout is:
+// struct tlsdesc {
+// ptrdiff_t (*entry) (struct tlsdesc *);
+// void *arg;
+// };
+static const uint8_t AArch64TlsdescGotAtomContent[16] = {0};
// .plt value (entry 0)
-const uint8_t AArch64Plt0AtomContent[32] = {
- 0xf0, 0x7b, 0xbf,
- 0xa9, // stp x16, x30, [sp,#-16]!
- 0x10, 0x00, 0x00,
- 0x90, // adrp x16, Page(eh_frame)
- 0x11, 0x02, 0x40,
- 0xf9, // ldr x17, [x16,#offset]
- 0x10, 0x02, 0x00,
- 0x91, // add x16, x16, #offset
- 0x20, 0x02, 0x1f,
- 0xd6, // br x17
- 0x1f, 0x20, 0x03,
- 0xd5, // nop
- 0x1f, 0x20, 0x03,
- 0xd5, // nop
- 0x1f, 0x20, 0x03,
- 0xd5 // nop
+static const uint8_t AArch64Plt0AtomContent[32] = {
+ 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]!
+ 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(eh_frame)
+ 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16,#offset]
+ 0x10, 0x02, 0x00, 0x91, // add x16, x16, #offset
+ 0x20, 0x02, 0x1f, 0xd6, // br x17
+ 0x1f, 0x20, 0x03, 0xd5, // nop
+ 0x1f, 0x20, 0x03, 0xd5, // nop
+ 0x1f, 0x20, 0x03, 0xd5 // nop
};
// .plt values (other entries)
-const uint8_t AArch64PltAtomContent[16] = {
- 0x10, 0x00, 0x00,
- 0x90, // adrp x16, PAGE(<GLOBAL_OFFSET_TABLE>)
- 0x11, 0x02, 0x40,
- 0xf9, // ldr x17, [x16,#offset]
- 0x10, 0x02, 0x00,
- 0x91, // add x16, x16, #offset
- 0x20, 0x02, 0x1f,
- 0xd6 // br x17
+static const uint8_t AArch64PltAtomContent[16] = {
+ 0x10, 0x00, 0x00, 0x90, // adrp x16, PAGE(<GLOBAL_OFFSET_TABLE>)
+ 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16,#offset]
+ 0x10, 0x02, 0x00, 0x91, // add x16, x16, #offset
+ 0x20, 0x02, 0x1f, 0xd6 // br x17
+};
+
+// .plt tlsdesc values
+static const uint8_t AArch64PltTlsdescAtomContent[32] = {
+ 0xe2, 0x0f, 0xbf, 0xa9, // stp x2, x3, [sp, #-16]
+ 0x02, 0x00, 0x00, 0x90, // adpr x2, 0
+ 0x03, 0x00, 0x00, 0x90, // adpr x3, 0
+ 0x42, 0x00, 0x40, 0xf9, // ldr x2, [x2, #0]
+ 0x63, 0x00, 0x00, 0x91, // add x3, x3, 0
+ 0x40, 0x00, 0x1f, 0xd6, // br x2
+ 0x1f, 0x20, 0x03, 0xd5, // nop
+ 0x1f, 0x20, 0x03, 0xd5 // nop
};
+namespace {
+
/// \brief Atoms that are used by AArch64 dynamic linking
class AArch64GOTAtom : public GOTAtom {
public:
- AArch64GOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {}
+ AArch64GOTAtom(const File &f) : GOTAtom(f, ".got") {}
ArrayRef<uint8_t> rawContent() const override {
return ArrayRef<uint8_t>(AArch64GotAtomContent, 8);
}
+
+protected:
+ // Constructor for AArch64GOTAtom
+ AArch64GOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {}
+};
+
+class AArch64GOTPLTAtom : public AArch64GOTAtom {
+public:
+ AArch64GOTPLTAtom(const File &f) : AArch64GOTAtom(f, ".got.plt") {}
};
+class AArch64TLSDESCGOTAtom : public AArch64GOTPLTAtom {
+public:
+ AArch64TLSDESCGOTAtom(const File &f) : AArch64GOTPLTAtom(f) {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return ArrayRef<uint8_t>(AArch64TlsdescGotAtomContent, 16);
+ }
+};
+
+
class AArch64PLT0Atom : public PLT0Atom {
public:
AArch64PLT0Atom(const File &f) : PLT0Atom(f) {}
@@ -84,13 +111,22 @@ public:
class AArch64PLTAtom : public PLTAtom {
public:
- AArch64PLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {}
+ AArch64PLTAtom(const File &f) : PLTAtom(f, ".plt") {}
ArrayRef<uint8_t> rawContent() const override {
return ArrayRef<uint8_t>(AArch64PltAtomContent, 16);
}
};
+class AArch64PLTTLSDESCAtom : public PLTAtom {
+public:
+ AArch64PLTTLSDESCAtom(const File &f) : PLTAtom(f, ".plt") {}
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return ArrayRef<uint8_t>(AArch64PltTlsdescAtomContent, 32);
+ }
+};
+
class ELFPassFile : public SimpleFile {
public:
ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") {
@@ -149,9 +185,16 @@ template <class Derived> class AArch64RelocationPass : public Pass {
break;
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_LD64_GOT_LO12_NC:
+ static_cast<Derived *>(this)->handleGOT(ref);
+ break;
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- static_cast<Derived *>(this)->handleGOT(ref);
+ static_cast<Derived *>(this)->handleGOTTPREL(ref);
+ break;
+ case R_AARCH64_TLSDESC_ADR_PAGE21:
+ case R_AARCH64_TLSDESC_LD64_LO12_NC:
+ case R_AARCH64_TLSDESC_ADD_LO12_NC:
+ static_cast<Derived *>(this)->handleTLSDESC(ref);
break;
}
}
@@ -164,9 +207,9 @@ protected:
auto plt = _pltMap.find(da);
if (plt != _pltMap.end())
return plt->second;
- auto ga = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt");
+ auto ga = new (_file._alloc) AArch64GOTPLTAtom(_file);
ga->addReferenceELF_AArch64(R_AARCH64_IRELATIVE, 0, da, 0);
- auto pa = new (_file._alloc) AArch64PLTAtom(_file, ".plt");
+ auto pa = new (_file._alloc) AArch64PLTAtom(_file);
pa->addReferenceELF_AArch64(R_AARCH64_PREL32, 2, ga, -4);
#ifndef NDEBUG
ga->_name = "__got_ifunc_";
@@ -193,11 +236,11 @@ protected:
}
/// \brief Create a GOT entry for the TP offset of a TLS atom.
- const GOTAtom *getGOTTPOFF(const Atom *atom) {
+ const GOTAtom *getGOTTPREL(const Atom *atom) {
auto got = _gotMap.find(atom);
if (got == _gotMap.end()) {
- auto g = new (_file._alloc) AArch64GOTAtom(_file, ".got");
- g->addReferenceELF_AArch64(R_AARCH64_GOTREL64, 0, atom, 0);
+ auto g = new (_file._alloc) AArch64GOTAtom(_file);
+ g->addReferenceELF_AArch64(R_AARCH64_TLS_TPREL64, 0, atom, 0);
#ifndef NDEBUG
g->_name = "__got_tls_";
g->_name += atom->name();
@@ -209,17 +252,53 @@ protected:
return got->second;
}
- /// \brief Create a TPOFF64 GOT entry and change the relocation to a PC32 to
- /// the GOT.
- void handleGOTTPOFF(const Reference &ref) {
- const_cast<Reference &>(ref).setTarget(getGOTTPOFF(ref.target()));
- const_cast<Reference &>(ref).setKindValue(R_AARCH64_PREL32);
+ /// \brief Create a GOT TPREL entry to local or external TLS variable.
+ std::error_code handleGOTTPREL(const Reference &ref) {
+ if (isa<DefinedAtom>(ref.target()) ||
+ isa<SharedLibraryAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getGOTTPREL(ref.target()));
+ return std::error_code();
+ }
+
+ /// \brief Generates a double GOT entry with R_AARCH64_TLSDESC dynamic
+ /// relocation reference. Since the dynamic relocation is resolved
+ /// lazily so the GOT associated should be in .got.plt.
+ const GOTAtom *getTLSDESCPLTEntry(const Atom *da) {
+ auto got = _gotMap.find(da);
+ if (got != _gotMap.end())
+ return got->second;
+ auto ga = new (_file._alloc) AArch64TLSDESCGOTAtom(_file);
+ ga->addReferenceELF_AArch64(R_AARCH64_TLSDESC, 0, da, 0);
+ auto pa = new (_file._alloc) AArch64PLTTLSDESCAtom(_file);
+ pa->addReferenceELF_AArch64(R_AARCH64_ADR_PREL_PG_HI21, 4, ga, 0);
+ pa->addReferenceELF_AArch64(R_AARCH64_ADR_PREL_PG_HI21, 8, ga, 0);
+ pa->addReferenceELF_AArch64(R_AARCH64_LDST64_ABS_LO12_NC, 12, ga, 0);
+ pa->addReferenceELF_AArch64(R_AARCH64_ADD_ABS_LO12_NC, 16, ga, 0);
+#ifndef NDEBUG
+ ga->_name = "__got_tlsdesc_";
+ ga->_name += da->name();
+ pa->_name = "__plt_tlsdesc_";
+ pa->_name += da->name();
+#endif
+ _gotMap[da] = ga;
+ _pltMap[da] = pa;
+ _tlsdescVector.push_back(ga);
+ _pltVector.push_back(pa);
+ return ga;
+ }
+
+ std::error_code handleTLSDESC(const Reference &ref) {
+ if (isa<DefinedAtom>(ref.target()) ||
+ isa<SharedLibraryAtom>(ref.target())) {
+ const_cast<Reference &>(ref).setTarget(getTLSDESCPLTEntry(ref.target()));
+ }
+ return std::error_code();
}
/// \brief Create a GOT entry containing 0.
const GOTAtom *getNullGOT() {
if (!_null) {
- _null = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt");
+ _null = new (_file._alloc) AArch64GOTPLTAtom(_file);
#ifndef NDEBUG
_null->_name = "__got_null";
#endif
@@ -230,7 +309,7 @@ protected:
const GOTAtom *getGOT(const DefinedAtom *da) {
auto got = _gotMap.find(da);
if (got == _gotMap.end()) {
- auto g = new (_file._alloc) AArch64GOTAtom(_file, ".got");
+ auto g = new (_file._alloc) AArch64GOTAtom(_file);
g->addReferenceELF_AArch64(R_AARCH64_ABS64, 0, da, 0);
#ifndef NDEBUG
g->_name = "__got_";
@@ -244,9 +323,7 @@ protected:
}
public:
- AArch64RelocationPass(const ELFLinkingContext &ctx)
- : _file(ctx), _ctx(ctx), _null(nullptr), _PLT0(nullptr), _got0(nullptr),
- _got1(nullptr) {}
+ AArch64RelocationPass(const ELFLinkingContext &ctx) : _file(ctx), _ctx(ctx) {}
/// \brief Do the pass.
///
@@ -256,32 +333,32 @@ public:
///
/// After all references are handled, the atoms created during that are all
/// added to mf.
- void perform(std::unique_ptr<MutableFile> &mf) override {
+ std::error_code perform(SimpleFile &mf) override {
ScopedTask task(getDefaultDomain(), "AArch64 GOT/PLT Pass");
DEBUG_WITH_TYPE(
"AArch64", llvm::dbgs() << "Undefined Atoms"
<< "\n";
for (const auto &atom
- : mf->undefined()) {
+ : mf.undefined()) {
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
} llvm::dbgs()
<< "Shared Library Atoms"
<< "\n";
for (const auto &atom
- : mf->sharedLibrary()) {
+ : mf.sharedLibrary()) {
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
} llvm::dbgs()
<< "Absolute Atoms"
<< "\n";
for (const auto &atom
- : mf->absolute()) {
+ : mf.absolute()) {
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
}
// Process all references.
llvm::dbgs()
<< "Defined Atoms"
<< "\n");
- for (const auto &atom : mf->defined()) {
+ for (const auto &atom : mf.defined()) {
for (const auto &ref : *atom) {
handleReference(*atom, *ref);
}
@@ -289,32 +366,39 @@ public:
// Add all created atoms to the link.
uint64_t ordinal = 0;
- if (_PLT0) {
- _PLT0->setOrdinal(ordinal++);
- mf->addAtom(*_PLT0);
+ if (_plt0) {
+ _plt0->setOrdinal(ordinal++);
+ mf.addAtom(*_plt0);
}
for (auto &plt : _pltVector) {
plt->setOrdinal(ordinal++);
- mf->addAtom(*plt);
+ mf.addAtom(*plt);
}
if (_null) {
_null->setOrdinal(ordinal++);
- mf->addAtom(*_null);
+ mf.addAtom(*_null);
}
- if (_PLT0) {
+ if (_plt0) {
_got0->setOrdinal(ordinal++);
_got1->setOrdinal(ordinal++);
- mf->addAtom(*_got0);
- mf->addAtom(*_got1);
+ mf.addAtom(*_got0);
+ mf.addAtom(*_got1);
}
for (auto &got : _gotVector) {
got->setOrdinal(ordinal++);
- mf->addAtom(*got);
+ mf.addAtom(*got);
+ }
+ // Add any tlsdesc GOT relocation after default PLT and iFUNC entries.
+ for (auto &tlsdesc : _tlsdescVector) {
+ tlsdesc->setOrdinal(ordinal++);
+ mf.addAtom(*tlsdesc);
}
for (auto obj : _objectVector) {
obj->setOrdinal(ordinal++);
- mf->addAtom(*obj);
+ mf.addAtom(*obj);
}
+
+ return std::error_code();
}
protected:
@@ -333,18 +417,19 @@ protected:
/// \brief the list of GOT/PLT atoms
std::vector<GOTAtom *> _gotVector;
+ std::vector<GOTAtom *> _tlsdescVector;
std::vector<PLTAtom *> _pltVector;
std::vector<ObjectAtom *> _objectVector;
/// \brief GOT entry that is always 0. Used for undefined weaks.
- GOTAtom *_null;
+ GOTAtom *_null = nullptr;
/// \brief The got and plt entries for .PLT0. This is used to call into the
/// dynamic linker for symbol resolution.
/// @{
- PLT0Atom *_PLT0;
- GOTAtom *_got0;
- GOTAtom *_got1;
+ PLT0Atom *_plt0 = nullptr;
+ GOTAtom *_got0 = nullptr;
+ GOTAtom *_got1 = nullptr;
/// @}
};
@@ -394,31 +479,31 @@ public:
: AArch64RelocationPass(ctx) {}
const PLT0Atom *getPLT0() {
- if (_PLT0)
- return _PLT0;
+ if (_plt0)
+ return _plt0;
// Fill in the null entry.
getNullGOT();
- _PLT0 = new (_file._alloc) AArch64PLT0Atom(_file);
- _got0 = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt");
- _got1 = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt");
- _PLT0->addReferenceELF_AArch64(R_AARCH64_ADR_GOT_PAGE, 4, _got0, 0);
- _PLT0->addReferenceELF_AArch64(R_AARCH64_LD64_GOT_LO12_NC, 8, _got1, 0);
- _PLT0->addReferenceELF_AArch64(ADD_AARCH64_GOTRELINDEX, 12, _got1, 0);
+ _plt0 = new (_file._alloc) AArch64PLT0Atom(_file);
+ _got0 = new (_file._alloc) AArch64GOTPLTAtom(_file);
+ _got1 = new (_file._alloc) AArch64GOTPLTAtom(_file);
+ _plt0->addReferenceELF_AArch64(R_AARCH64_ADR_GOT_PAGE, 4, _got0, 0);
+ _plt0->addReferenceELF_AArch64(R_AARCH64_LD64_GOT_LO12_NC, 8, _got1, 0);
+ _plt0->addReferenceELF_AArch64(ADD_AARCH64_GOTRELINDEX, 12, _got1, 0);
#ifndef NDEBUG
- _PLT0->_name = "__PLT0";
+ _plt0->_name = "__PLT0";
_got0->_name = "__got0";
_got1->_name = "__got1";
#endif
- return _PLT0;
+ return _plt0;
}
const PLTAtom *getPLTEntry(const Atom *a) {
auto plt = _pltMap.find(a);
if (plt != _pltMap.end())
return plt->second;
- auto ga = new (_file._alloc) AArch64GOTAtom(_file, ".got.plt");
+ auto ga = new (_file._alloc) AArch64GOTPLTAtom(_file);
ga->addReferenceELF_AArch64(R_AARCH64_JUMP_SLOT, 0, a, 0);
- auto pa = new (_file._alloc) AArch64PLTAtom(_file, ".plt");
+ auto pa = new (_file._alloc) AArch64PLTAtom(_file);
pa->addReferenceELF_AArch64(R_AARCH64_ADR_GOT_PAGE, 0, ga, 0);
pa->addReferenceELF_AArch64(R_AARCH64_LD64_GOT_LO12_NC, 4, ga, 0);
pa->addReferenceELF_AArch64(ADD_AARCH64_GOTRELINDEX, 8, ga, 0);
@@ -485,7 +570,7 @@ public:
const GOTAtom *getSharedGOT(const SharedLibraryAtom *sla) {
auto got = _gotMap.find(sla);
if (got == _gotMap.end()) {
- auto g = new (_file._alloc) AArch64GOTAtom(_file, ".got");
+ auto g = new (_file._alloc) AArch64GOTAtom(_file);
g->addReferenceELF_AArch64(R_AARCH64_GLOB_DAT, 0, sla, 0);
#ifndef NDEBUG
g->_name = "__got_";