summaryrefslogtreecommitdiff
path: root/lib/Target/AArch64/AArch64PLT.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/AArch64/AArch64PLT.cpp')
-rw-r--r--lib/Target/AArch64/AArch64PLT.cpp171
1 files changed, 171 insertions, 0 deletions
diff --git a/lib/Target/AArch64/AArch64PLT.cpp b/lib/Target/AArch64/AArch64PLT.cpp
new file mode 100644
index 0000000..c24327d
--- /dev/null
+++ b/lib/Target/AArch64/AArch64PLT.cpp
@@ -0,0 +1,171 @@
+//===- AArch64PLT.cpp -----------------------------------------------------===//
+//
+// The MCLinker Project
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "AArch64GOT.h"
+#include "AArch64PLT.h"
+#include "AArch64RelocationHelpers.h"
+
+#include <new>
+
+#include <llvm/Support/Casting.h>
+
+#include <mcld/LD/LDSection.h>
+#include <mcld/Support/MsgHandling.h>
+
+using namespace mcld;
+
+AArch64PLT0::AArch64PLT0(SectionData& pParent)
+ : PLT::Entry<sizeof(aarch64_plt0)>(pParent) {}
+
+AArch64PLT1::AArch64PLT1(SectionData& pParent)
+ : PLT::Entry<sizeof(aarch64_plt1)>(pParent) {}
+
+//===----------------------------------------------------------------------===//
+// AArch64PLT
+
+AArch64PLT::AArch64PLT(LDSection& pSection, AArch64GOT &pGOTPLT)
+ : PLT(pSection), m_GOT(pGOTPLT) {
+ new AArch64PLT0(*m_pSectionData);
+}
+
+AArch64PLT::~AArch64PLT()
+{
+}
+
+bool AArch64PLT::hasPLT1() const
+{
+ return (m_pSectionData->size() > 1);
+}
+
+void AArch64PLT::finalizeSectionSize()
+{
+ uint64_t size = (m_pSectionData->size() - 1) * sizeof(aarch64_plt1) +
+ sizeof(aarch64_plt0);
+ m_Section.setSize(size);
+
+ uint32_t offset = 0;
+ SectionData::iterator frag, fragEnd = m_pSectionData->end();
+ for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) {
+ frag->setOffset(offset);
+ offset += frag->size();
+ }
+}
+
+AArch64PLT1* AArch64PLT::create()
+{
+ AArch64PLT1* plt1_entry = new (std::nothrow) AArch64PLT1(*m_pSectionData);
+ if (!plt1_entry)
+ fatal(diag::fail_allocate_memory_plt);
+ return plt1_entry;
+}
+
+void AArch64PLT::applyPLT0()
+{
+ // malloc plt0
+ iterator first = m_pSectionData->getFragmentList().begin();
+ assert(first != m_pSectionData->getFragmentList().end() &&
+ "FragmentList is empty, applyPLT0 failed!");
+ AArch64PLT0* plt0 = &(llvm::cast<AArch64PLT0>(*first));
+ uint32_t* data = NULL;
+ data = static_cast<uint32_t*>(malloc(AArch64PLT0::EntrySize));
+ if (data == NULL)
+ fatal(diag::fail_allocate_memory_plt);
+ memcpy(data, aarch64_plt0, AArch64PLT0::EntrySize);
+
+ // apply plt0
+ uint64_t plt_base = m_Section.addr();
+ assert(plt_base && ".plt base address is NULL!");
+ uint64_t got_base = m_GOT.addr();
+ assert(got_base && ".got base address is NULL!");
+
+ // apply 2nd instruction
+ // get the address of got entry 2
+ uint64_t got_ent2_base = got_base + sizeof(AArch64GOTEntry::EntrySize) * 2;
+ // compute the immediate
+ AArch64Relocator::DWord imm = helper_get_page_address(got_ent2_base) -
+ helper_get_page_address(plt_base + (sizeof(AArch64PLT0::EntrySize) * 8));
+ data[1] = helper_reencode_adr_imm(data[1], imm >> 12);
+ // apply 3rd instruction
+ data[2] = helper_reencode_add_imm(data[2],
+ helper_get_page_offset(got_ent2_base) >> 3);
+ // apply 4th instruction
+ data[3] = helper_reencode_add_imm(data[3],
+ helper_get_page_offset(got_ent2_base));
+ plt0->setValue(reinterpret_cast<unsigned char*>(data));
+}
+
+void AArch64PLT::applyPLT1()
+{
+ uint64_t plt_base = m_Section.addr();
+ assert(plt_base && ".plt base address is NULL!");
+
+ uint64_t got_base = m_GOT.addr();
+ assert(got_base && ".got base address is NULL!");
+
+ AArch64PLT::iterator it = m_pSectionData->begin();
+ AArch64PLT::iterator ie = m_pSectionData->end();
+ assert(it != ie && "FragmentList is empty, applyPLT1 failed!");
+
+ uint32_t GOTEntrySize = AArch64GOTEntry::EntrySize;
+ // first gotplt1 address
+ uint32_t GOTEntryAddress = got_base + GOTEntrySize * 3;
+ // first plt1 address
+ uint32_t PLTEntryAddress = plt_base + AArch64PLT0::EntrySize;
+
+ ++it; //skip PLT0
+ uint32_t PLT1EntrySize = AArch64PLT1::EntrySize;
+ AArch64PLT1* plt1 = NULL;
+
+ uint32_t* Out = NULL;
+ while (it != ie) {
+ plt1 = &(llvm::cast<AArch64PLT1>(*it));
+ Out = static_cast<uint32_t*>(malloc(AArch64PLT1::EntrySize));
+ memcpy(Out, aarch64_plt1, AArch64PLT1::EntrySize);
+ // apply 1st instruction
+ AArch64Relocator::DWord imm = helper_get_page_address(GOTEntryAddress) -
+ helper_get_page_address(PLTEntryAddress);
+ Out[0] = helper_reencode_adr_imm(Out[0], imm >> 12);
+ // apply 2nd instruction
+ Out[1] = helper_reencode_add_imm(
+ Out[1], helper_get_page_offset(GOTEntryAddress) >> 3);
+ // apply 3rd instruction
+ Out[2] = helper_reencode_add_imm(
+ Out[2], helper_get_page_offset(GOTEntryAddress));
+
+ plt1->setValue(reinterpret_cast<unsigned char*>(Out));
+ ++it;
+
+ GOTEntryAddress += GOTEntrySize;
+ PLTEntryAddress += PLT1EntrySize;
+ }
+
+ m_GOT.applyGOTPLT(plt_base);
+}
+
+uint64_t AArch64PLT::emit(MemoryRegion& pRegion)
+{
+ uint64_t result = 0x0;
+ iterator it = begin();
+
+ unsigned char* buffer = pRegion.begin();
+ memcpy(buffer, llvm::cast<AArch64PLT0>((*it)).getValue(),
+ AArch64PLT0::EntrySize);
+ result += AArch64PLT0::EntrySize;
+ ++it;
+
+ AArch64PLT1* plt1 = NULL;
+ AArch64PLT::iterator ie = end();
+ while (it != ie) {
+ plt1 = &(llvm::cast<AArch64PLT1>(*it));
+ memcpy(buffer + result, plt1->getValue(), AArch64PLT1::EntrySize);
+ result += AArch64PLT1::EntrySize;
+ ++it;
+ }
+ return result;
+}
+