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 1337b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/LD/LDSection.h" 1437b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/Support/MsgHandling.h" 15551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 16551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines#include <llvm/Support/Casting.h> 17551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 1837b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include <new> 19551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 2037b74a387bb3993387029859c2d9d051c41c724eStephen Hinesnamespace mcld { 21551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 22551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen HinesAArch64PLT0::AArch64PLT0(SectionData& pParent) 2337b74a387bb3993387029859c2d9d051c41c724eStephen Hines : PLT::Entry<sizeof(aarch64_plt0)>(pParent) { 2437b74a387bb3993387029859c2d9d051c41c724eStephen Hines} 25551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 26551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen HinesAArch64PLT1::AArch64PLT1(SectionData& pParent) 2737b74a387bb3993387029859c2d9d051c41c724eStephen Hines : PLT::Entry<sizeof(aarch64_plt1)>(pParent) { 2837b74a387bb3993387029859c2d9d051c41c724eStephen Hines} 29551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 30551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines//===----------------------------------------------------------------------===// 31551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines// AArch64PLT 32551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 3337b74a387bb3993387029859c2d9d051c41c724eStephen HinesAArch64PLT::AArch64PLT(LDSection& pSection, AArch64GOT& pGOTPLT) 3437b74a387bb3993387029859c2d9d051c41c724eStephen Hines : PLT(pSection), m_GOT(pGOTPLT) { 35551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines new AArch64PLT0(*m_pSectionData); 36551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 37551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 3837b74a387bb3993387029859c2d9d051c41c724eStephen HinesAArch64PLT::~AArch64PLT() { 39551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 40551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 4137b74a387bb3993387029859c2d9d051c41c724eStephen Hinesbool AArch64PLT::hasPLT1() const { 42551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return (m_pSectionData->size() > 1); 43551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 44551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 4537b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid AArch64PLT::finalizeSectionSize() { 46551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint64_t size = (m_pSectionData->size() - 1) * sizeof(aarch64_plt1) + 47551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines sizeof(aarch64_plt0); 48551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines m_Section.setSize(size); 49551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 50551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint32_t offset = 0; 51551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines SectionData::iterator frag, fragEnd = m_pSectionData->end(); 52551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) { 53551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines frag->setOffset(offset); 54551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines offset += frag->size(); 55551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines } 56551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 57551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 5837b74a387bb3993387029859c2d9d051c41c724eStephen HinesAArch64PLT1* AArch64PLT::create() { 59551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64PLT1* plt1_entry = new (std::nothrow) AArch64PLT1(*m_pSectionData); 60551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines if (!plt1_entry) 61551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines fatal(diag::fail_allocate_memory_plt); 62551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return plt1_entry; 63551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 64551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 6537b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid AArch64PLT::applyPLT0() { 66551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // malloc plt0 67551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines iterator first = m_pSectionData->getFragmentList().begin(); 68551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines assert(first != m_pSectionData->getFragmentList().end() && 69551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines "FragmentList is empty, applyPLT0 failed!"); 70551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64PLT0* plt0 = &(llvm::cast<AArch64PLT0>(*first)); 71551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint32_t* data = NULL; 72551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines data = static_cast<uint32_t*>(malloc(AArch64PLT0::EntrySize)); 73551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines if (data == NULL) 74551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines fatal(diag::fail_allocate_memory_plt); 75551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines memcpy(data, aarch64_plt0, AArch64PLT0::EntrySize); 76551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 77551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // apply plt0 78551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint64_t plt_base = m_Section.addr(); 79551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines assert(plt_base && ".plt base address is NULL!"); 80551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint64_t got_base = m_GOT.addr(); 81551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines assert(got_base && ".got base address is NULL!"); 82551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 83551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // apply 2nd instruction 84551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // get the address of got entry 2 85551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint64_t got_ent2_base = got_base + sizeof(AArch64GOTEntry::EntrySize) * 2; 86551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // compute the immediate 8737b74a387bb3993387029859c2d9d051c41c724eStephen Hines AArch64Relocator::DWord imm = 8837b74a387bb3993387029859c2d9d051c41c724eStephen Hines helper_get_page_address(got_ent2_base) - 8937b74a387bb3993387029859c2d9d051c41c724eStephen Hines helper_get_page_address(plt_base + (sizeof(AArch64PLT0::EntrySize) * 8)); 90551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines data[1] = helper_reencode_adr_imm(data[1], imm >> 12); 91551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // apply 3rd instruction 92551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines data[2] = helper_reencode_add_imm(data[2], 93551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines helper_get_page_offset(got_ent2_base) >> 3); 94551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // apply 4th instruction 9537b74a387bb3993387029859c2d9d051c41c724eStephen Hines data[3] = 9637b74a387bb3993387029859c2d9d051c41c724eStephen Hines helper_reencode_add_imm(data[3], helper_get_page_offset(got_ent2_base)); 97551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines plt0->setValue(reinterpret_cast<unsigned char*>(data)); 98551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 99551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 10037b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid AArch64PLT::applyPLT1() { 101551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint64_t plt_base = m_Section.addr(); 102551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines assert(plt_base && ".plt base address is NULL!"); 103551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 104551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint64_t got_base = m_GOT.addr(); 105551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines assert(got_base && ".got base address is NULL!"); 106551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 107551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64PLT::iterator it = m_pSectionData->begin(); 108551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64PLT::iterator ie = m_pSectionData->end(); 109551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines assert(it != ie && "FragmentList is empty, applyPLT1 failed!"); 110551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 111551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint32_t GOTEntrySize = AArch64GOTEntry::EntrySize; 112551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // first gotplt1 address 113551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint32_t GOTEntryAddress = got_base + GOTEntrySize * 3; 114551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // first plt1 address 115551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint32_t PLTEntryAddress = plt_base + AArch64PLT0::EntrySize; 116551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 11737b74a387bb3993387029859c2d9d051c41c724eStephen Hines ++it; // skip PLT0 118551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint32_t PLT1EntrySize = AArch64PLT1::EntrySize; 119551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64PLT1* plt1 = NULL; 120551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 121551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint32_t* Out = NULL; 122551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines while (it != ie) { 123551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines plt1 = &(llvm::cast<AArch64PLT1>(*it)); 124551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines Out = static_cast<uint32_t*>(malloc(AArch64PLT1::EntrySize)); 125551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines memcpy(Out, aarch64_plt1, AArch64PLT1::EntrySize); 126551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // apply 1st instruction 127551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64Relocator::DWord imm = helper_get_page_address(GOTEntryAddress) - 128551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines helper_get_page_address(PLTEntryAddress); 129551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines Out[0] = helper_reencode_adr_imm(Out[0], imm >> 12); 130551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // apply 2nd instruction 131551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines Out[1] = helper_reencode_add_imm( 132551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines Out[1], helper_get_page_offset(GOTEntryAddress) >> 3); 133551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines // apply 3rd instruction 13437b74a387bb3993387029859c2d9d051c41c724eStephen Hines Out[2] = helper_reencode_add_imm(Out[2], 13537b74a387bb3993387029859c2d9d051c41c724eStephen Hines helper_get_page_offset(GOTEntryAddress)); 136551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 137551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines plt1->setValue(reinterpret_cast<unsigned char*>(Out)); 138551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines ++it; 139551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 140551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines GOTEntryAddress += GOTEntrySize; 141551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines PLTEntryAddress += PLT1EntrySize; 142551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines } 143551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 144551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines m_GOT.applyGOTPLT(plt_base); 145551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 146551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 14737b74a387bb3993387029859c2d9d051c41c724eStephen Hinesuint64_t AArch64PLT::emit(MemoryRegion& pRegion) { 148551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines uint64_t result = 0x0; 149551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines iterator it = begin(); 150551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 151551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines unsigned char* buffer = pRegion.begin(); 15237b74a387bb3993387029859c2d9d051c41c724eStephen Hines memcpy(buffer, 15337b74a387bb3993387029859c2d9d051c41c724eStephen Hines llvm::cast<AArch64PLT0>((*it)).getValue(), 15437b74a387bb3993387029859c2d9d051c41c724eStephen Hines AArch64PLT0::EntrySize); 155551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines result += AArch64PLT0::EntrySize; 156551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines ++it; 157551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 158551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64PLT1* plt1 = NULL; 159551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines AArch64PLT::iterator ie = end(); 160551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines while (it != ie) { 161551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines plt1 = &(llvm::cast<AArch64PLT1>(*it)); 162551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines memcpy(buffer + result, plt1->getValue(), AArch64PLT1::EntrySize); 163551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines result += AArch64PLT1::EntrySize; 164551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines ++it; 165551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines } 166551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines return result; 167551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines} 168551ae4ebd3e9d137ea668fb83ae4a55b8cfba451Stephen Hines 16937b74a387bb3993387029859c2d9d051c41c724eStephen Hines} // namespace mcld 170