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