diff options
Diffstat (limited to 'lib/Target/AArch64/AArch64PLT.cpp')
-rw-r--r-- | lib/Target/AArch64/AArch64PLT.cpp | 171 |
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; +} + |