1//===- AArch64PLT.cpp -----------------------------------------------------===// 2// 3// The MCLinker Project 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9#include "AArch64GOT.h" 10#include "AArch64PLT.h" 11#include "AArch64RelocationHelpers.h" 12 13#include "mcld/LD/LDSection.h" 14#include "mcld/Support/MsgHandling.h" 15 16#include <llvm/Support/Casting.h> 17 18#include <new> 19 20namespace mcld { 21 22AArch64PLT0::AArch64PLT0(SectionData& pParent) 23 : PLT::Entry<sizeof(aarch64_plt0)>(pParent) { 24} 25 26AArch64PLT1::AArch64PLT1(SectionData& pParent) 27 : PLT::Entry<sizeof(aarch64_plt1)>(pParent) { 28} 29 30//===----------------------------------------------------------------------===// 31// AArch64PLT 32 33AArch64PLT::AArch64PLT(LDSection& pSection, AArch64GOT& pGOTPLT) 34 : PLT(pSection), m_GOT(pGOTPLT) { 35 new AArch64PLT0(*m_pSectionData); 36} 37 38AArch64PLT::~AArch64PLT() { 39} 40 41bool AArch64PLT::hasPLT1() const { 42 return (m_pSectionData->size() > 1); 43} 44 45void AArch64PLT::finalizeSectionSize() { 46 uint64_t size = (m_pSectionData->size() - 1) * sizeof(aarch64_plt1) + 47 sizeof(aarch64_plt0); 48 m_Section.setSize(size); 49 50 uint32_t offset = 0; 51 SectionData::iterator frag, fragEnd = m_pSectionData->end(); 52 for (frag = m_pSectionData->begin(); frag != fragEnd; ++frag) { 53 frag->setOffset(offset); 54 offset += frag->size(); 55 } 56} 57 58AArch64PLT1* AArch64PLT::create() { 59 AArch64PLT1* plt1_entry = new (std::nothrow) AArch64PLT1(*m_pSectionData); 60 if (!plt1_entry) 61 fatal(diag::fail_allocate_memory_plt); 62 return plt1_entry; 63} 64 65void AArch64PLT::applyPLT0() { 66 // malloc plt0 67 iterator first = m_pSectionData->getFragmentList().begin(); 68 assert(first != m_pSectionData->getFragmentList().end() && 69 "FragmentList is empty, applyPLT0 failed!"); 70 AArch64PLT0* plt0 = &(llvm::cast<AArch64PLT0>(*first)); 71 uint32_t* data = NULL; 72 data = static_cast<uint32_t*>(malloc(AArch64PLT0::EntrySize)); 73 if (data == NULL) 74 fatal(diag::fail_allocate_memory_plt); 75 memcpy(data, aarch64_plt0, AArch64PLT0::EntrySize); 76 77 // apply plt0 78 uint64_t plt_base = m_Section.addr(); 79 assert(plt_base && ".plt base address is NULL!"); 80 uint64_t got_base = m_GOT.addr(); 81 assert(got_base && ".got base address is NULL!"); 82 83 // apply 2nd instruction 84 // get the address of got entry 2 85 uint64_t got_ent2_base = got_base + sizeof(AArch64GOTEntry::EntrySize) * 2; 86 // compute the immediate 87 AArch64Relocator::DWord imm = 88 helper_get_page_address(got_ent2_base) - 89 helper_get_page_address(plt_base + (sizeof(AArch64PLT0::EntrySize) * 8)); 90 data[1] = helper_reencode_adr_imm(data[1], imm >> 12); 91 // apply 3rd instruction 92 data[2] = helper_reencode_add_imm(data[2], 93 helper_get_page_offset(got_ent2_base) >> 3); 94 // apply 4th instruction 95 data[3] = 96 helper_reencode_add_imm(data[3], helper_get_page_offset(got_ent2_base)); 97 plt0->setValue(reinterpret_cast<unsigned char*>(data)); 98} 99 100void AArch64PLT::applyPLT1() { 101 uint64_t plt_base = m_Section.addr(); 102 assert(plt_base && ".plt base address is NULL!"); 103 104 uint64_t got_base = m_GOT.addr(); 105 assert(got_base && ".got base address is NULL!"); 106 107 AArch64PLT::iterator it = m_pSectionData->begin(); 108 AArch64PLT::iterator ie = m_pSectionData->end(); 109 assert(it != ie && "FragmentList is empty, applyPLT1 failed!"); 110 111 uint32_t GOTEntrySize = AArch64GOTEntry::EntrySize; 112 // first gotplt1 address 113 uint32_t GOTEntryAddress = got_base + GOTEntrySize * 3; 114 // first plt1 address 115 uint32_t PLTEntryAddress = plt_base + AArch64PLT0::EntrySize; 116 117 ++it; // skip PLT0 118 uint32_t PLT1EntrySize = AArch64PLT1::EntrySize; 119 AArch64PLT1* plt1 = NULL; 120 121 uint32_t* Out = NULL; 122 while (it != ie) { 123 plt1 = &(llvm::cast<AArch64PLT1>(*it)); 124 Out = static_cast<uint32_t*>(malloc(AArch64PLT1::EntrySize)); 125 memcpy(Out, aarch64_plt1, AArch64PLT1::EntrySize); 126 // apply 1st instruction 127 AArch64Relocator::DWord imm = helper_get_page_address(GOTEntryAddress) - 128 helper_get_page_address(PLTEntryAddress); 129 Out[0] = helper_reencode_adr_imm(Out[0], imm >> 12); 130 // apply 2nd instruction 131 Out[1] = helper_reencode_add_imm( 132 Out[1], helper_get_page_offset(GOTEntryAddress) >> 3); 133 // apply 3rd instruction 134 Out[2] = helper_reencode_add_imm(Out[2], 135 helper_get_page_offset(GOTEntryAddress)); 136 137 plt1->setValue(reinterpret_cast<unsigned char*>(Out)); 138 ++it; 139 140 GOTEntryAddress += GOTEntrySize; 141 PLTEntryAddress += PLT1EntrySize; 142 } 143 144 m_GOT.applyGOTPLT(plt_base); 145} 146 147uint64_t AArch64PLT::emit(MemoryRegion& pRegion) { 148 uint64_t result = 0x0; 149 iterator it = begin(); 150 151 unsigned char* buffer = pRegion.begin(); 152 memcpy(buffer, 153 llvm::cast<AArch64PLT0>((*it)).getValue(), 154 AArch64PLT0::EntrySize); 155 result += AArch64PLT0::EntrySize; 156 ++it; 157 158 AArch64PLT1* plt1 = NULL; 159 AArch64PLT::iterator ie = end(); 160 while (it != ie) { 161 plt1 = &(llvm::cast<AArch64PLT1>(*it)); 162 memcpy(buffer + result, plt1->getValue(), AArch64PLT1::EntrySize); 163 result += AArch64PLT1::EntrySize; 164 ++it; 165 } 166 return result; 167} 168 169} // namespace mcld 170