//===- 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; }