1551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines//===- AArch64PLT.cpp -----------------------------------------------------===// 2551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// 3551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// The MCLinker Project 4551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// 5551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// This file is distributed under the University of Illinois Open Source 6551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// License. See LICENSE.TXT for details. 7551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// 8551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines//===----------------------------------------------------------------------===// 9551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include "AArch64GOT.h" 10551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include "AArch64PLT.h" 11551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include "AArch64RelocationHelpers.h" 12551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 13551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include <new> 14551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 15551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include <llvm/Support/Casting.h> 16551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 17551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include <mcld/LD/LDSection.h> 18551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include <mcld/Support/MsgHandling.h> 19551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 20551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hinesusing namespace mcld; 21551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 22551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen HinesAArch64PLT0::AArch64PLT0(SectionData& pParent) 23551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines : PLT::Entry<sizeof(aarch64_plt0)>(pParent) {} 24551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 25551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen HinesAArch64PLT1::AArch64PLT1(SectionData& pParent) 26551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines : PLT::Entry<sizeof(aarch64_plt1)>(pParent) {} 27551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 28551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines//===----------------------------------------------------------------------===// 29551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// AArch64PLT 30551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 31551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen HinesAArch64PLT::AArch64PLT(LDSection& pSection, AArch64GOT &pGOTPLT) 32551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines : PLT(pSection), m_GOT(pGOTPLT) { 33551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines new AArch64PLT0(*m_pSectionData); 34551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 35551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 36551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen HinesAArch64PLT::~AArch64PLT() 37551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines{ 38551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 39551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 40551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hinesbool AArch64PLT::hasPLT1() const 41551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines{ 42551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return (m_pSectionData->size() > 1); 43551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 44551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 45551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hinesvoid AArch64PLT::finalizeSectionSize() 46551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines{ 47551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint64_t size = (m_pSectionData->size() - 1) * sizeof(aarch64_plt1) + 48551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines sizeof(aarch64_plt0); 49551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines m_Section.setSize(size); 50551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 51551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint32_t offset = 0; 52551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines SectionData::iterator frag, fragEnd = m_pSectionData->end(); 53551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) { 54551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines frag->setOffset(offset); 55551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines offset += frag->size(); 56551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines } 57551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 58551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 59551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen HinesAArch64PLT1* AArch64PLT::create() 60551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines{ 61551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64PLT1* plt1_entry = new (std::nothrow) AArch64PLT1(*m_pSectionData); 62551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines if (!plt1_entry) 63551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines fatal(diag::fail_allocate_memory_plt); 64551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return plt1_entry; 65551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 66551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 67551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hinesvoid AArch64PLT::applyPLT0() 68551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines{ 69551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // malloc plt0 70551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines iterator first = m_pSectionData->getFragmentList().begin(); 71551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines assert(first != m_pSectionData->getFragmentList().end() && 72551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines "FragmentList is empty, applyPLT0 failed!"); 73551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64PLT0* plt0 = &(llvm::cast<AArch64PLT0>(*first)); 74551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint32_t* data = NULL; 75551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines data = static_cast<uint32_t*>(malloc(AArch64PLT0::EntrySize)); 76551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines if (data == NULL) 77551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines fatal(diag::fail_allocate_memory_plt); 78551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines memcpy(data, aarch64_plt0, AArch64PLT0::EntrySize); 79551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 80551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // apply plt0 81551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint64_t plt_base = m_Section.addr(); 82551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines assert(plt_base && ".plt base address is NULL!"); 83551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint64_t got_base = m_GOT.addr(); 84551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines assert(got_base && ".got base address is NULL!"); 85551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 86551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // apply 2nd instruction 87551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // get the address of got entry 2 88551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint64_t got_ent2_base = got_base + sizeof(AArch64GOTEntry::EntrySize) * 2; 89551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // compute the immediate 90551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64Relocator::DWord imm = helper_get_page_address(got_ent2_base) - 91551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines helper_get_page_address(plt_base + (sizeof(AArch64PLT0::EntrySize) * 8)); 92551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines data[1] = helper_reencode_adr_imm(data[1], imm >> 12); 93551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // apply 3rd instruction 94551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines data[2] = helper_reencode_add_imm(data[2], 95551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines helper_get_page_offset(got_ent2_base) >> 3); 96551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // apply 4th instruction 97551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines data[3] = helper_reencode_add_imm(data[3], 98551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines helper_get_page_offset(got_ent2_base)); 99551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines plt0->setValue(reinterpret_cast<unsigned char*>(data)); 100551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 101551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 102551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hinesvoid AArch64PLT::applyPLT1() 103551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines{ 104551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint64_t plt_base = m_Section.addr(); 105551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines assert(plt_base && ".plt base address is NULL!"); 106551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 107551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint64_t got_base = m_GOT.addr(); 108551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines assert(got_base && ".got base address is NULL!"); 109551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 110551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64PLT::iterator it = m_pSectionData->begin(); 111551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64PLT::iterator ie = m_pSectionData->end(); 112551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines assert(it != ie && "FragmentList is empty, applyPLT1 failed!"); 113551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 114551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint32_t GOTEntrySize = AArch64GOTEntry::EntrySize; 115551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // first gotplt1 address 116551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint32_t GOTEntryAddress = got_base + GOTEntrySize * 3; 117551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // first plt1 address 118551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint32_t PLTEntryAddress = plt_base + AArch64PLT0::EntrySize; 119551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 120551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines ++it; //skip PLT0 121551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint32_t PLT1EntrySize = AArch64PLT1::EntrySize; 122551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64PLT1* plt1 = NULL; 123551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 124551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint32_t* Out = NULL; 125551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines while (it != ie) { 126551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines plt1 = &(llvm::cast<AArch64PLT1>(*it)); 127551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines Out = static_cast<uint32_t*>(malloc(AArch64PLT1::EntrySize)); 128551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines memcpy(Out, aarch64_plt1, AArch64PLT1::EntrySize); 129551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // apply 1st instruction 130551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64Relocator::DWord imm = helper_get_page_address(GOTEntryAddress) - 131551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines helper_get_page_address(PLTEntryAddress); 132551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines Out[0] = helper_reencode_adr_imm(Out[0], imm >> 12); 133551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // apply 2nd instruction 134551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines Out[1] = helper_reencode_add_imm( 135551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines Out[1], helper_get_page_offset(GOTEntryAddress) >> 3); 136551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // apply 3rd instruction 137551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines Out[2] = helper_reencode_add_imm( 138551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines Out[2], helper_get_page_offset(GOTEntryAddress)); 139551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 140551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines plt1->setValue(reinterpret_cast<unsigned char*>(Out)); 141551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines ++it; 142551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 143551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines GOTEntryAddress += GOTEntrySize; 144551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines PLTEntryAddress += PLT1EntrySize; 145551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines } 146551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 147551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines m_GOT.applyGOTPLT(plt_base); 148551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 149551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 150551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hinesuint64_t AArch64PLT::emit(MemoryRegion& pRegion) 151551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines{ 152551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint64_t result = 0x0; 153551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines iterator it = begin(); 154551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 155551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines unsigned char* buffer = pRegion.begin(); 156551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines memcpy(buffer, llvm::cast<AArch64PLT0>((*it)).getValue(), 157551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64PLT0::EntrySize); 158551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines result += AArch64PLT0::EntrySize; 159551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines ++it; 160551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 161551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64PLT1* plt1 = NULL; 162551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64PLT::iterator ie = end(); 163551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines while (it != ie) { 164551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines plt1 = &(llvm::cast<AArch64PLT1>(*it)); 165551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines memcpy(buffer + result, plt1->getValue(), AArch64PLT1::EntrySize); 166551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines result += AArch64PLT1::EntrySize; 167551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines ++it; 168551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines } 169551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return result; 170551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 171551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 172